diff --git a/CHANGELOG.md b/CHANGELOG.md index d66a79e..45d7c66 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,31 +1,3 @@ -## 0.2.5 - -* Ratio options can be provided in ImageEditor as well as in ImageCropper - -## 0.2.4 - -* Ratio options can be provided in constructor -* Allowed feature list can be provided in constructor -* Image compress height & width parameter added - -## 0.2.3 - -* Bug fixes - -## 0.2.2 - -* Dependencies updated -* Bug fixes - -## 0.2.1 - -* Dependencies updated -* Bug fixes - -## 0.2.0 - -* Dependencies updated - ## 0.1.8 * Performance optimization diff --git a/LICENSE b/LICENSE index 7edf0b6..e965e4a 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 hsbijarniya@gmail.com +Copyright (c) 2022 hsbijarniya@gmail.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 1c9b95d..9eb55b8 100755 --- a/README.md +++ b/README.md @@ -94,28 +94,29 @@ import 'package:image_editor_plus/utils.dart'; // to jpeg final convertedImage = await ImageUtils.convert( - image: data, // <-- Uint8List/path of image + image: data, // <-- Uint8List of image format: 'jpg', quality: 80, ); -// to heic +// to png final convertedImage = await ImageUtils.convert( - image: data, // <-- Uint8List/path of image - format: 'heic', + image: data, // <-- Uint8List of image + format: 'png', quality: 80, ); -// to png +// to webp else jpg (note: webp required one alernate target format in case it's not available) final convertedImage = await ImageUtils.convert( - image: data, // <-- Uint8List/path of image - format: 'png', + image: data, // <-- Uint8List of image + format: 'webp|jpg', + quality: 80, ); -// to webp +// to webp else png (note: webp required one alernate target format in case it's not available) final convertedImage = await ImageUtils.convert( - image: data, // <-- Uint8List/path of image - format: 'webp', + image: data, // <-- Uint8List of image + format: 'webp|png', quality: 80, ); ``` diff --git a/example/lib/main.dart b/example/lib/main.dart index 3b2ae02..09efb7c 100755 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_editor_plus/image_editor_plus.dart'; -import 'package:image_editor_plus/utils.dart'; void main() { runApp( @@ -13,11 +12,11 @@ void main() { class ImageEditorExample extends StatefulWidget { const ImageEditorExample({ - super.key, - }); + Key? key, + }) : super(key: key); @override - createState() => _ImageEditorExampleState(); + _ImageEditorExampleState createState() => _ImageEditorExampleState(); } class _ImageEditorExampleState extends State { @@ -77,18 +76,8 @@ class _ImageEditorExampleState extends State { imageData, ], allowMultiple: true, - features: const ImageEditorFeatures( - pickFromGallery: true, - captureFromCamera: true, - crop: true, - blur: true, - brush: true, - emoji: true, - filters: true, - flip: true, - rotate: true, - text: true, - ), + allowCamera: true, + allowGallery: true, ), ), ); diff --git a/lib/data/editor_mode.dart b/lib/data/editor_mode.dart deleted file mode 100644 index 2a38cba..0000000 --- a/lib/data/editor_mode.dart +++ /dev/null @@ -1,4 +0,0 @@ -enum EditorMode { - brush, - filter, -} diff --git a/lib/data/layer.dart b/lib/data/layer.dart index bbda6dd..fb7ab37 100755 --- a/lib/data/layer.dart +++ b/lib/data/layer.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:image_editor_plus/data/image_item.dart'; +import 'package:nb_utils/nb_utils.dart'; /// Layer class with some common properties class Layer { @@ -34,6 +35,7 @@ class EmojiLayerData extends Layer { double size; EmojiLayerData({ + Key? key, this.text = '', this.size = 64, Offset? offset, @@ -54,6 +56,7 @@ class ImageLayerData extends Layer { double size; ImageLayerData({ + Key? key, required this.image, this.size = 64, Offset? offset, @@ -79,7 +82,7 @@ class TextLayerData extends Layer { TextLayerData({ required this.text, this.size = 64, - this.color = Colors.white, + this.color = white, this.background = Colors.transparent, this.backgroundOpacity = 1, this.align = TextAlign.left, diff --git a/lib/image_editor_plus.dart b/lib/image_editor_plus.dart index ee2eed4..3032120 100644 --- a/lib/image_editor_plus.dart +++ b/lib/image_editor_plus.dart @@ -20,11 +20,10 @@ import 'package:image_editor_plus/layers/background_layer.dart'; import 'package:image_editor_plus/layers/emoji_layer.dart'; import 'package:image_editor_plus/layers/image_layer.dart'; import 'package:image_editor_plus/layers/text_layer.dart'; -import 'package:image_editor_plus/loading_screen.dart'; import 'package:image_editor_plus/modules/all_emojies.dart'; import 'package:image_editor_plus/modules/text.dart'; -import 'package:image_editor_plus/utils.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:nb_utils/nb_utils.dart'; import 'package:screenshot/screenshot.dart'; import 'modules/colors_picker.dart'; @@ -46,47 +45,22 @@ class ImageEditor extends StatelessWidget { final Directory? savePath; final int maxLength; final bool allowGallery, allowCamera, allowMultiple; - final ImageEditorFeatures features; - final List cropAvailableRatios; - const ImageEditor({ - super.key, - this.image, - this.images, - this.savePath, - @Deprecated('Use features instead') this.allowCamera = false, - @Deprecated('Use features instead') this.allowGallery = false, - this.allowMultiple = false, - this.maxLength = 99, - Color? appBar, - this.features = const ImageEditorFeatures( - pickFromGallery: true, - captureFromCamera: true, - crop: true, - blur: true, - brush: true, - emoji: true, - filters: true, - flip: true, - rotate: true, - text: true, - ), - this.cropAvailableRatios = const [ - AspectRatioOption(title: 'Freeform'), - AspectRatioOption(title: '1:1', ratio: 1), - AspectRatioOption(title: '4:3', ratio: 4 / 3), - AspectRatioOption(title: '5:4', ratio: 5 / 4), - AspectRatioOption(title: '7:5', ratio: 7 / 5), - AspectRatioOption(title: '16:9', ratio: 16 / 9), - ], - }); + const ImageEditor( + {Key? key, + this.image, + this.images, + this.savePath, + this.allowCamera = false, + this.allowGallery = false, + this.allowMultiple = false, + this.maxLength = 99, + Color? appBar}) + : super(key: key); @override Widget build(BuildContext context) { - if (images == null && - image == null && - !features.captureFromCamera && - !features.pickFromGallery) { + if (images != null && image == null && !allowCamera && !allowGallery) { throw Exception( 'No image to work with, provide an image or allow the image picker.'); } @@ -95,17 +69,17 @@ class ImageEditor extends StatelessWidget { return MultiImageEditor( images: images ?? [], savePath: savePath, + allowCamera: allowCamera, + allowGallery: allowGallery, allowMultiple: allowMultiple, maxLength: maxLength, - features: features, - cropAvailableRatios: cropAvailableRatios, ); } else { return SingleImageEditor( image: image, savePath: savePath, - features: features, - cropAvailableRatios: cropAvailableRatios, + allowCamera: allowCamera, + allowGallery: allowGallery, ); } } @@ -119,9 +93,7 @@ class ImageEditor extends StatelessWidget { /// Set custom theme properties default is dark theme with white text static ThemeData theme = ThemeData( scaffoldBackgroundColor: Colors.black, - colorScheme: const ColorScheme.dark( - background: Colors.black, - ), + backgroundColor: Colors.black, appBarTheme: const AppBarTheme( backgroundColor: Colors.black87, iconTheme: IconThemeData(color: Colors.white), @@ -147,41 +119,19 @@ class MultiImageEditor extends StatefulWidget { final List images; final int maxLength; final bool allowGallery, allowCamera, allowMultiple; - final ImageEditorFeatures features; - final List cropAvailableRatios; const MultiImageEditor({ - super.key, + Key? key, this.images = const [], this.savePath, - @Deprecated('Use features instead') this.allowCamera = false, - @Deprecated('Use features instead') this.allowGallery = false, + this.allowCamera = false, + this.allowGallery = false, this.allowMultiple = false, this.maxLength = 99, - this.features = const ImageEditorFeatures( - pickFromGallery: true, - captureFromCamera: true, - crop: true, - blur: true, - brush: true, - emoji: true, - filters: true, - flip: true, - rotate: true, - text: true, - ), - this.cropAvailableRatios = const [ - AspectRatioOption(title: 'Freeform'), - AspectRatioOption(title: '1:1', ratio: 1), - AspectRatioOption(title: '4:3', ratio: 4 / 3), - AspectRatioOption(title: '5:4', ratio: 5 / 4), - AspectRatioOption(title: '7:5', ratio: 7 / 5), - AspectRatioOption(title: '16:9', ratio: 16 / 9), - ], - }); + }) : super(key: key); @override - createState() => _MultiImageEditorState(); + _MultiImageEditorState createState() => _MultiImageEditorState(); } class _MultiImageEditorState extends State { @@ -206,10 +156,8 @@ class _MultiImageEditorState extends State { actions: [ const BackButton(), const Spacer(), - if (images.length < widget.maxLength && - widget.features.pickFromGallery) + if (images.length < widget.maxLength && widget.allowGallery) IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: const Icon(Icons.photo), onPressed: () async { var selected = await picker.pickMultiImage(); @@ -217,11 +165,9 @@ class _MultiImageEditorState extends State { images.addAll(selected.map((e) => ImageItem(e)).toList()); setState(() {}); }, - ), - if (images.length < widget.maxLength && - widget.features.captureFromCamera) + ).paddingSymmetric(horizontal: 8), + if (images.length < widget.maxLength && widget.allowCamera) IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: const Icon(Icons.camera_alt), onPressed: () async { var selected = @@ -232,14 +178,13 @@ class _MultiImageEditorState extends State { images.add(ImageItem(selected)); setState(() {}); }, - ), + ).paddingSymmetric(horizontal: 8), IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: const Icon(Icons.check), onPressed: () async { Navigator.pop(context, images); }, - ), + ).paddingSymmetric(horizontal: 8), ], ), body: Column( @@ -254,42 +199,38 @@ class _MultiImageEditorState extends State { const SizedBox(width: 32), for (var image in images) Stack(children: [ - GestureDetector( - onTap: () async { - var img = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => SingleImageEditor( - image: image, - ), - ), - ); - - if (img != null) { - image.load(img); - setState(() {}); - } - }, - child: Container( - margin: const EdgeInsets.only( - top: 32, right: 32, bottom: 32), - width: 200, - height: 300, - decoration: BoxDecoration( - color: Colors.transparent, - border: - Border.all(color: Colors.white.withAlpha(80)), - borderRadius: BorderRadius.circular(8), + Container( + margin: const EdgeInsets.only( + top: 32, right: 32, bottom: 32), + width: 200, + height: 300, + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all(color: white.withAlpha(80)), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Image.memory( + image.image, + fit: BoxFit.cover, ), - child: ClipRRect( - borderRadius: BorderRadius.circular(4), - child: Image.memory( - image.image, - fit: BoxFit.cover, + ), + ).onTap(() async { + var img = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => SingleImageEditor( + image: image, ), ), - ), - ), + ); + + if (img != null) { + image.load(img); + setState(() {}); + } + }), Positioned( top: 36, right: 36, @@ -298,7 +239,7 @@ class _MultiImageEditorState extends State { width: 32, alignment: Alignment.center, decoration: BoxDecoration( - color: Colors.black.withAlpha(60), + color: black.withAlpha(60), borderRadius: BorderRadius.circular(16), ), child: IconButton( @@ -321,7 +262,7 @@ class _MultiImageEditorState extends State { width: 38, alignment: Alignment.center, decoration: BoxDecoration( - color: Colors.black.withAlpha(100), + color: black.withAlpha(100), borderRadius: const BorderRadius.only( topRight: Radius.circular(19), ), @@ -367,40 +308,18 @@ class SingleImageEditor extends StatefulWidget { final dynamic image; final List? imageList; final bool allowCamera, allowGallery; - final ImageEditorFeatures features; - final List cropAvailableRatios; const SingleImageEditor({ - super.key, + Key? key, this.savePath, this.image, this.imageList, - @Deprecated('Use features instead') this.allowCamera = false, - @Deprecated('Use features instead') this.allowGallery = false, - this.features = const ImageEditorFeatures( - pickFromGallery: true, - captureFromCamera: true, - crop: true, - blur: true, - brush: true, - emoji: true, - filters: true, - flip: true, - rotate: true, - text: true, - ), - this.cropAvailableRatios = const [ - AspectRatioOption(title: 'Freeform'), - AspectRatioOption(title: '1:1', ratio: 1), - AspectRatioOption(title: '4:3', ratio: 4 / 3), - AspectRatioOption(title: '5:4', ratio: 5 / 4), - AspectRatioOption(title: '7:5', ratio: 7 / 5), - AspectRatioOption(title: '16:9', ratio: 16 / 9), - ], - }); + this.allowCamera = false, + this.allowGallery = false, + }) : super(key: key); @override - createState() => _SingleImageEditorState(); + _SingleImageEditorState createState() => _SingleImageEditorState(); } class _SingleImageEditorState extends State { @@ -408,7 +327,7 @@ class _SingleImageEditorState extends State { Offset offset1 = Offset.zero; Offset offset2 = Offset.zero; - final scaffoldGlobalKey = GlobalKey(); + final scaf = GlobalKey(); final GlobalKey container = GlobalKey(); final GlobalKey globalKey = GlobalKey(); @@ -423,90 +342,68 @@ class _SingleImageEditorState extends State { List get filterActions { return [ const BackButton(), - SizedBox( - width: MediaQuery.of(context).size.width - 48, - child: SingleChildScrollView( - reverse: true, - scrollDirection: Axis.horizontal, - 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(() {}); - }, - ), - if (widget.features.pickFromGallery) - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: const Icon(Icons.photo), - onPressed: () async { - var image = - await picker.pickImage(source: ImageSource.gallery); - - if (image == null) return; - - loadImage(image); - }, - ), - if (widget.features.captureFromCamera) - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: const Icon(Icons.camera_alt), - onPressed: () async { - var image = - await picker.pickImage(source: ImageSource.camera); - - if (image == null) return; - - loadImage(image); - }, - ), - IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), - icon: const Icon(Icons.check), - onPressed: () async { - resetTransformation(); - setState(() {}); - - LoadingScreen(scaffoldGlobalKey).show(); - - var binaryIntList = - await screenshotController.capture(pixelRatio: pixelRatio); - - LoadingScreen(scaffoldGlobalKey).hide(); - - if (mounted) Navigator.pop(context, binaryIntList); - }, - ), - ]), - ), - ), + const Spacer(), + IconButton( + icon: Icon(Icons.undo, + color: + layers.length > 1 || removedLayers.isNotEmpty ? white : 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(() {}); + }, + ).paddingSymmetric(horizontal: 8), + IconButton( + icon: Icon(Icons.redo, color: undoLayers.isNotEmpty ? white : grey), + onPressed: () { + if (undoLayers.isEmpty) return; + + layers.add(undoLayers.removeLast()); + + setState(() {}); + }, + ).paddingSymmetric(horizontal: 8), + if (widget.allowGallery) + IconButton( + icon: const Icon(Icons.photo), + onPressed: () async { + var image = await picker.pickImage(source: ImageSource.gallery); + + if (image == null) return; + + loadImage(image); + }, + ).paddingSymmetric(horizontal: 8), + if (widget.allowCamera) + IconButton( + icon: const Icon(Icons.camera_alt), + onPressed: () async { + var image = await picker.pickImage(source: ImageSource.camera); + + if (image == null) return; + + loadImage(image); + }, + ).paddingSymmetric(horizontal: 8), + IconButton( + icon: const Icon(Icons.check), + onPressed: () async { + resetTransformation(); + + var binaryIntList = + await screenshotController.capture(pixelRatio: pixelRatio); + + Navigator.pop(context, binaryIntList); + }, + ).paddingSymmetric(horizontal: 8), ]; } @@ -579,20 +476,12 @@ class _SingleImageEditorState extends State { if (layerItem is BackgroundBlurLayerData && layerItem.radius > 0) { return BackgroundBlurLayer( layerData: layerItem, - onUpdate: () { - setState(() {}); - }, ); } // Emoji layer if (layerItem is EmojiLayerData) { - return EmojiLayer( - layerData: layerItem, - onUpdate: () { - setState(() {}); - }, - ); + return EmojiLayer(layerData: layerItem); } // Text layer @@ -617,84 +506,71 @@ class _SingleImageEditorState extends State { return Theme( data: ImageEditor.theme, child: Scaffold( - key: scaffoldGlobalKey, - body: Stack(children: [ - GestureDetector( - onScaleUpdate: (details) { - // print(details); - - // move - if (details.pointerCount == 1) { - // print(details.focalPointDelta); - x += details.focalPointDelta.dx; - y += details.focalPointDelta.dy; + key: scaf, + appBar: AppBar( + automaticallyImplyLeading: false, + actions: filterActions, + ), + body: 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); setState(() {}); } - - // scale - if (details.pointerCount == 2) { - // print([details.horizontalScale, details.verticalScale]); - if (details.horizontalScale != 1) { - scaleFactor = lastScaleFactor * - math.min(details.horizontalScale, details.verticalScale); - setState(() {}); - } - } - }, - onScaleEnd: (details) { - lastScaleFactor = scaleFactor; - }, - child: Center( - child: SizedBox( - height: currentImage.height / pixelRatio, - width: currentImage.width / pixelRatio, - child: Screenshot( - controller: screenshotController, - child: RotatedBox( - quarterTurns: rotateValue, - child: Transform( - transform: Matrix4( - 1, - 0, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 0, - 1, - 0, - x, - y, - 0, - 1 / scaleFactor, - )..rotateY(flipValue), - alignment: FractionalOffset.center, - child: layersStack, - ), + } + }, + onScaleEnd: (details) { + lastScaleFactor = scaleFactor; + }, + child: Center( + child: SizedBox( + height: currentImage.height / pixelRatio, + width: currentImage.width / pixelRatio, + child: Screenshot( + controller: screenshotController, + child: RotatedBox( + quarterTurns: rotateValue, + child: Transform( + transform: Matrix4( + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + x, + y, + 0, + 1 / scaleFactor, + )..rotateY(flipValue), + alignment: FractionalOffset.center, + child: layersStack, ), ), ), ), ), - Positioned( - top: 0, - left: 0, - right: 0, - child: SafeArea( - child: Container( - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.25), - ), - child: Row( - children: filterActions, - ), - ), - ), - ) - ]), + ), bottomNavigationBar: Container( // color: Colors.black45, alignment: Alignment.bottomCenter, @@ -708,385 +584,358 @@ class _SingleImageEditorState extends State { // ], ), child: SafeArea( - child: SingleChildScrollView( + child: ListView( scrollDirection: Axis.horizontal, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (widget.features.crop) - BottomButton( - icon: Icons.crop, - text: i18n('Crop'), - onTap: () async { - resetTransformation(); - LoadingScreen(scaffoldGlobalKey).show(); - - var mergedImage = await getMergedImage(); - - LoadingScreen(scaffoldGlobalKey).hide(); - - if (!mounted) return; - - Uint8List? croppedImage = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ImageCropper( - image: mergedImage!, - availableRatios: widget.cropAvailableRatios, - ), - ), - ); + children: [ + BottomButton( + icon: Icons.crop, + text: 'Crop', + onTap: () async { + resetTransformation(); + + var mergedImage = await getMergedImage(); + + Uint8List? croppedImage = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ImageCropper( + image: mergedImage!, + ), + ), + ); - if (croppedImage == null) return; + if (croppedImage == null) return; - flipValue = 0; - rotateValue = 0; + flipValue = 0; + rotateValue = 0; - await currentImage.load(croppedImage); - setState(() {}); - }, - ), - if (widget.features.brush) - BottomButton( - icon: Icons.edit, - text: i18n('Brush'), - onTap: () async { - var drawing = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ImageEditorDrawing( - image: currentImage, - ), - ), - ); + await currentImage.load(croppedImage); + setState(() {}); + }, + ), + BottomButton( + icon: Icons.edit, + text: 'Brush', + onTap: () async { + var drawing = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ImageEditorDrawing( + image: currentImage.image, + ), + ), + ); - if (drawing != null) { - undoLayers.clear(); - removedLayers.clear(); + if (drawing != null) { + undoLayers.clear(); + removedLayers.clear(); - layers.add( - ImageLayerData( - image: ImageItem(drawing), - offset: Offset( - -currentImage.width / 4, - -currentImage.height / 4, - ), - ), - ); + layers.add( + ImageLayerData( + image: ImageItem(drawing), + ), + ); - setState(() {}); - } - }, - ), - if (widget.features.text) - BottomButton( - icon: Icons.text_fields, - text: i18n('Text'), - onTap: () async { - TextLayerData? layer = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TextEditorImage(), - ), - ); + setState(() {}); + } + }, + ), + BottomButton( + icon: Icons.text_fields, + text: 'Text', + onTap: () async { + TextLayerData? layer = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TextEditorImage(), + ), + ); - if (layer == null) return; + if (layer == null) return; - undoLayers.clear(); - removedLayers.clear(); + undoLayers.clear(); + removedLayers.clear(); - layers.add(layer); + layers.add(layer); - setState(() {}); - }, - ), - if (widget.features.flip) - BottomButton( - icon: Icons.flip, - text: i18n('Flip'), - onTap: () { - setState(() { - flipValue = flipValue == 0 ? math.pi : 0; - }); - }, - ), - if (widget.features.rotate) - BottomButton( - icon: Icons.rotate_left, - text: i18n('Rotate left'), - onTap: () { - var t = currentImage.width; - currentImage.width = currentImage.height; - currentImage.height = t; - - rotateValue--; - setState(() {}); - }, - ), - if (widget.features.rotate) - BottomButton( - icon: Icons.rotate_right, - text: i18n('Rotate right'), - onTap: () { - var t = currentImage.width; - currentImage.width = currentImage.height; - currentImage.height = t; - - rotateValue++; - setState(() {}); - }, - ), - if (widget.features.blur) - BottomButton( - icon: Icons.blur_on, - text: i18n('Blur'), - onTap: () { - var blurLayer = BackgroundBlurLayerData( - color: Colors.transparent, - radius: 0.0, - opacity: 0.0, - ); + setState(() {}); + }, + ), + BottomButton( + icon: Icons.flip, + text: 'Flip', + onTap: () { + setState(() { + flipValue = flipValue == 0 ? math.pi : 0; + }); + }, + ), + BottomButton( + icon: Icons.rotate_left, + text: 'Rotate left', + onTap: () { + var t = currentImage.width; + currentImage.width = currentImage.height; + currentImage.height = t; + + rotateValue--; + setState(() {}); + }, + ), + BottomButton( + icon: Icons.rotate_right, + text: 'Rotate right', + onTap: () { + var t = currentImage.width; + currentImage.width = currentImage.height; + currentImage.height = t; + + rotateValue++; + setState(() {}); + }, + ), + BottomButton( + icon: Icons.blur_on, + text: 'Blur', + onTap: () { + var blurLayer = BackgroundBlurLayerData( + color: Colors.transparent, + radius: 0.0, + opacity: 0.0, + ); - undoLayers.clear(); - removedLayers.clear(); - layers.add(blurLayer); - setState(() {}); + undoLayers.clear(); + removedLayers.clear(); + layers.add(blurLayer); + setState(() {}); - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10)), - ), - context: context, - builder: (context) { - return StatefulBuilder( - builder: (context, setS) { - return SingleChildScrollView( - child: Container( - decoration: const BoxDecoration( - color: Colors.black87, - borderRadius: BorderRadius.only( - topRight: Radius.circular(10), - topLeft: Radius.circular(10)), + showModalBottomSheet( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(10), + topLeft: Radius.circular(10)), + ), + context: context, + builder: (context) { + return StatefulBuilder( + builder: (context, setS) { + return SingleChildScrollView( + child: Container( + decoration: const BoxDecoration( + color: Colors.black87, + borderRadius: BorderRadius.only( + topRight: Radius.circular(10), + topLeft: Radius.circular(10)), + ), + padding: const EdgeInsets.all(20), + height: 400, + child: Column( + children: [ + Center( + child: Text( + i18n('Slider Filter Color').toUpperCase(), + style: + const TextStyle(color: Colors.white), + )), + const Divider(), + const SizedBox(height: 20.0), + Text( + i18n('Slider Color'), + style: + const TextStyle(color: Colors.white), ), - padding: const EdgeInsets.all(20), - height: 400, - child: Column( - children: [ - Center( - child: Text( - i18n('Slider Filter Color') - .toUpperCase(), - style: const TextStyle( - color: Colors.white), - )), - const Divider(), - const SizedBox(height: 20.0), - 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) { - setS(() { - setState(() { - blurLayer.color = - Color(value); - }); - }); - }, - ), - ), - TextButton( - child: Text( - i18n('Reset'), - ), - onPressed: () { + const SizedBox(height: 10), + Row(children: [ + Expanded( + child: BarColorPicker( + width: 300, + thumbColor: white, + cornerRadius: 10, + pickMode: PickMode.color, + colorListener: (int value) { + setS(() { setState(() { - setS(() { - blurLayer.color = - Colors.transparent; - }); + blurLayer.color = Color(value); }); - }, - ) - ]), - const SizedBox(height: 5.0), - Text( - i18n('Blur Radius'), - style: const TextStyle( - color: Colors.white), + }); + }, ), - const SizedBox(height: 10.0), - Row(children: [ - Expanded( - child: Slider( - activeColor: Colors.white, - inactiveColor: Colors.grey, - value: blurLayer.radius, - min: 0.0, - max: 10.0, - onChanged: (v) { - setS(() { - setState(() { - blurLayer.radius = v; - }); - }); - }, - ), - ), - TextButton( - child: Text( - i18n('Reset'), - ), - onPressed: () { - setS(() { - setState(() { - blurLayer.color = - Colors.white; - }); - }); - }, - ) - ]), - const SizedBox(height: 5.0), - Text( - i18n('Color Opacity'), - style: const TextStyle( - color: Colors.white), + ), + TextButton( + child: Text( + i18n('Reset'), ), - const SizedBox(height: 10.0), - Row(children: [ - Expanded( - child: Slider( - activeColor: Colors.white, - inactiveColor: Colors.grey, - value: blurLayer.opacity, - min: 0.00, - max: 1.0, - onChanged: (v) { - setS(() { - setState(() { - blurLayer.opacity = v; - }); - }); - }, - ), - ), - TextButton( - child: Text( - i18n('Reset'), - ), - onPressed: () { - setS(() { - setState(() { - blurLayer.opacity = 0.0; - }); + onPressed: () { + setState(() { + setS(() { + blurLayer.color = + Colors.transparent; + }); + }); + }, + ) + ]), + const SizedBox(height: 5.0), + Text( + i18n('Blur Radius'), + style: + const TextStyle(color: Colors.white), + ), + const SizedBox(height: 10.0), + Row(children: [ + Expanded( + child: Slider( + activeColor: white, + inactiveColor: Colors.grey, + value: blurLayer.radius, + min: 0.0, + max: 10.0, + onChanged: (v) { + setS(() { + setState(() { + blurLayer.radius = v; }); - }, - ) - ]), - ], + }); + }, + ), + ), + TextButton( + child: Text( + i18n('Reset'), + ), + onPressed: () { + setS(() { + setState(() { + blurLayer.color = Colors.white; + }); + }); + }, + ) + ]), + const SizedBox(height: 5.0), + Text( + i18n('Color Opacity'), + style: + const TextStyle(color: Colors.white), ), - ), - ); - }, + const SizedBox(height: 10.0), + Row(children: [ + Expanded( + child: Slider( + activeColor: white, + inactiveColor: Colors.grey, + value: blurLayer.opacity, + min: 0.00, + max: 1.0, + onChanged: (v) { + setS(() { + setState(() { + blurLayer.opacity = v; + }); + }); + }, + ), + ), + TextButton( + child: Text( + i18n('Reset'), + ), + onPressed: () { + setS(() { + setState(() { + blurLayer.opacity = 0.0; + }); + }); + }, + ) + ]), + ], + ), + ), ); }, ); }, - ), - // BottomButton( - // icon: FontAwesomeIcons.eraser, - // text: 'Eraser', - // onTap: () { - // _controller.clear(); - // layers.removeWhere((layer) => layer['type'] == 'drawing'); - // setState(() {}); - // }, - // ), - if (widget.features.filters) - BottomButton( - icon: Icons.photo, - text: i18n('Filter'), - onTap: () async { - resetTransformation(); - - /// Use case: if you don't want to stack your filter, use - /// this logic. Along with code on line 888 and - /// remove line 889 - // for (int i = 1; i < layers.length; i++) { - // if (layers[i] is BackgroundLayerData) { - // layers.removeAt(i); - // break; - // } - // } - var mergedImage = await getMergedImage(); - - if (!mounted) return; - - Uint8List? filterAppliedImage = await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ImageFilters( - image: mergedImage!, - ), - ), - ); + ); + }, + ), + // BottomButton( + // icon: FontAwesomeIcons.eraser, + // text: 'Eraser', + // onTap: () { + // _controller.clear(); + // layers.removeWhere((layer) => layer['type'] == 'drawing'); + // setState(() {}); + // }, + // ), + BottomButton( + icon: Icons.photo, + text: 'Filter', + onTap: () async { + resetTransformation(); + + /// Use case: if you don't want to stack your filter, use + /// this logic. Along with code on line 888 and + /// remove line 889 + // for (int i = 1; i < layers.length; i++) { + // if (layers[i] is BackgroundLayerData) { + // layers.removeAt(i); + // break; + // } + // } + var mergedImage = await getMergedImage(); + + Uint8List? filterAppliedImage = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ImageFilters( + image: mergedImage!, + ), + ), + ); - if (filterAppliedImage == null) return; + if (filterAppliedImage == null) return; - removedLayers.clear(); - undoLayers.clear(); + removedLayers.clear(); + undoLayers.clear(); - var layer = BackgroundLayerData( - file: ImageItem(filterAppliedImage), - ); + var layer = BackgroundLayerData( + file: ImageItem(filterAppliedImage), + ); - /// Use case, if you don't want your filter to effect your - /// other elements such as emoji and text. Use insert - /// instead of add like in line 888 - //layers.insert(1, layer); - layers.add(layer); + /// Use case, if you don't want your filter to effect your + /// other elements such as emoji and text. Use insert + /// instead of add like in line 888 + //layers.insert(1, layer); + layers.add(layer); - await layer.file.status; + await layer.file.status; - setState(() {}); + setState(() {}); + }, + ), + BottomButton( + icon: FontAwesomeIcons.faceSmile, + text: 'Emoji', + onTap: () async { + EmojiLayerData? layer = await showModalBottomSheet( + context: context, + backgroundColor: black, + builder: (BuildContext context) { + return const Emojies(); }, - ), - if (widget.features.emoji) - BottomButton( - icon: FontAwesomeIcons.faceSmile, - text: i18n('Emoji'), - onTap: () async { - EmojiLayerData? layer = await showModalBottomSheet( - context: context, - backgroundColor: Colors.black, - builder: (BuildContext context) { - return const Emojies(); - }, - ); + ); - if (layer == null) return; + if (layer == null) return; - undoLayers.clear(); - removedLayers.clear(); - layers.add(layer); + undoLayers.clear(); + removedLayers.clear(); + layers.add(layer); - setState(() {}); - }, - ), - ], - ), + setState(() {}); + }, + ), + ], ), ), ), @@ -1116,33 +965,30 @@ class BottomButton extends StatelessWidget { final String text; const BottomButton({ - super.key, + Key? key, this.onTap, this.onLongPress, required this.icon, required this.text, - }); + }) : super(key: key); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, onLongPress: onLongPress, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Column( - children: [ - Icon( - icon, - color: Colors.white, - ), - const SizedBox(height: 8), - Text( - i18n(text), - ), - ], - ), - ), + child: Column( + children: [ + Icon( + icon, + color: Colors.white, + ), + const SizedBox(height: 8), + Text( + i18n(text), + ), + ], + ).paddingSymmetric(horizontal: 16), ); } } @@ -1150,23 +996,11 @@ class BottomButton extends StatelessWidget { /// Crop given image with various aspect ratios class ImageCropper extends StatefulWidget { final Uint8List image; - final List availableRatios; - const ImageCropper({ - super.key, - required this.image, - this.availableRatios = const [ - AspectRatioOption(title: 'Freeform'), - AspectRatioOption(title: '1:1', ratio: 1), - AspectRatioOption(title: '4:3', ratio: 4 / 3), - AspectRatioOption(title: '5:4', ratio: 5 / 4), - AspectRatioOption(title: '7:5', ratio: 7 / 5), - AspectRatioOption(title: '16:9', ratio: 16 / 9), - ], - }); + const ImageCropper({Key? key, required this.image}) : super(key: key); @override - createState() => _ImageCropperState(); + _ImageCropperState createState() => _ImageCropperState(); } class _ImageCropperState extends State { @@ -1180,9 +1014,6 @@ class _ImageCropperState extends State { @override void initState() { - if (widget.availableRatios.isNotEmpty) { - aspectRatio = aspectRatioOriginal = widget.availableRatios.first.ratio; - } _controller.currentState?.rotate(right: true); super.initState(); @@ -1200,7 +1031,6 @@ class _ImageCropperState extends State { appBar: AppBar( actions: [ IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: const Icon(Icons.check), onPressed: () async { var state = _controller.currentState; @@ -1209,13 +1039,13 @@ class _ImageCropperState extends State { var data = await cropImageDataWithNativeLibrary(state: state); - if (mounted) Navigator.pop(context, data); + Navigator.pop(context, data); }, - ), + ).paddingSymmetric(horizontal: 8), ], ), body: Container( - color: Colors.black, + color: black, child: ExtendedImage.memory( widget.image, cacheRawData: true, @@ -1294,56 +1124,45 @@ class _ImageCropperState extends State { decoration: const BoxDecoration( boxShadow: [ BoxShadow( - color: Colors.black, + color: black, blurRadius: 10, ), ], ), - child: SingleChildScrollView( + child: ListView( scrollDirection: Axis.horizontal, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (aspectRatioOriginal != null && - aspectRatioOriginal != 1) - IconButton( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - icon: Icon( - Icons.portrait, - color: isLandscape ? Colors.grey : Colors.white, - ), - onPressed: () { - isLandscape = false; - if (aspectRatioOriginal != null) { - aspectRatio = 1 / aspectRatioOriginal!; - } - setState(() {}); - }, - ), - if (aspectRatioOriginal != null && - aspectRatioOriginal != 1) - IconButton( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - icon: Icon( - Icons.landscape, - color: isLandscape ? Colors.white : Colors.grey, - ), - onPressed: () { - isLandscape = true; - aspectRatio = aspectRatioOriginal!; - setState(() {}); - }, - ), - for (var ratio in widget.availableRatios) - imageRatioButton(ratio.ratio, i18n(ratio.title)), - ], - ), + children: [ + IconButton( + icon: Icon( + Icons.portrait, + color: isLandscape ? gray : white, + ).paddingSymmetric(horizontal: 8, vertical: 4), + onPressed: () { + isLandscape = false; + if (aspectRatioOriginal != null) { + aspectRatio = 1 / aspectRatioOriginal!; + } + setState(() {}); + }, + ), + IconButton( + icon: Icon( + Icons.landscape, + color: isLandscape ? white : gray, + ).paddingSymmetric(horizontal: 8, vertical: 4), + onPressed: () { + isLandscape = true; + aspectRatio = aspectRatioOriginal!; + setState(() {}); + }, + ), + imageRatioButton(null, 'Freeform'), + imageRatioButton(1, 'Square'), + imageRatioButton(4 / 3, '4:3'), + imageRatioButton(5 / 4, '5:4'), + imageRatioButton(7 / 5, '7:5'), + imageRatioButton(16 / 9, '16:9'), + ], ), ), ], @@ -1364,7 +1183,8 @@ class _ImageCropperState extends State { final bool flipVertical = action.flipX; final Uint8List img = state.rawImageData; - final option = image_editor.ImageEditorOption(); + final image_editor.ImageEditorOption option = + image_editor.ImageEditorOption(); if (action.needCrop) { option.addOption(image_editor.ClipOption.fromRect(cropRect!)); @@ -1394,23 +1214,19 @@ class _ImageCropperState extends State { return TextButton( onPressed: () { aspectRatioOriginal = ratio; - if (aspectRatioOriginal != null && isLandscape == false) { aspectRatio = 1 / aspectRatioOriginal!; } else { aspectRatio = aspectRatioOriginal; } - setState(() {}); }, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - child: Text( - i18n(title), - style: TextStyle( - color: aspectRatioOriginal == ratio ? Colors.white : Colors.grey, - ), - )), + child: Text( + i18n(title), + style: TextStyle( + color: aspectRatioOriginal == ratio ? white : gray, + ), + ).paddingSymmetric(horizontal: 8, vertical: 4), ); } } @@ -1423,13 +1239,13 @@ class ImageFilters extends StatefulWidget { final bool useCache; const ImageFilters({ - super.key, + Key? key, required this.image, this.useCache = true, - }); + }) : super(key: key); @override - createState() => _ImageFiltersState(); + _ImageFiltersState createState() => _ImageFiltersState(); } class _ImageFiltersState extends State { @@ -1456,13 +1272,12 @@ class _ImageFiltersState extends State { appBar: AppBar( actions: [ IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: const Icon(Icons.check), onPressed: () async { var data = await screenshotController.capture(); - if (mounted) Navigator.pop(context, data); + Navigator.pop(context, data); }, - ), + ).paddingSymmetric(horizontal: 8), ], ), body: Center( @@ -1530,38 +1345,35 @@ class _ImageFiltersState extends State { } Widget filterPreviewButton({required filter, required String name}) { - return GestureDetector( - onTap: () { - selectedFilter = filter; - setState(() {}); - }, - child: Column(children: [ - Container( - height: 64, - width: 64, - margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(48), - border: Border.all( - color: Colors.black, - width: 2, - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(48), - child: FilterAppliedImage( - image: widget.image, - filter: filter, - fit: BoxFit.cover, - ), + return Column(children: [ + Container( + height: 64, + width: 64, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(48), + border: Border.all( + color: Colors.black, + width: 2, ), ), - Text( - i18n(name), - style: const TextStyle(fontSize: 12), + child: ClipRRect( + borderRadius: BorderRadius.circular(48), + child: FilterAppliedImage( + image: widget.image, + filter: filter, + fit: BoxFit.cover, + ), ), - ]), - ); + ), + Text( + i18n(name), + style: const TextStyle(fontSize: 12), + ), + ]).onTap(() { + selectedFilter = filter; + setState(() {}); + }); } } @@ -1574,13 +1386,13 @@ class FilterAppliedImage extends StatelessWidget { final double opacity; FilterAppliedImage({ - super.key, + Key? key, required this.image, required this.filter, this.fit, this.onProcess, this.opacity = 1, - }) { + }) : super(key: key) { // process filter in background if (onProcess != null) { // no filter supplied @@ -1623,18 +1435,20 @@ class FilterAppliedImage extends StatelessWidget { /// Show image drawing surface over image class ImageEditorDrawing extends StatefulWidget { - final ImageItem image; + final Uint8List image; const ImageEditorDrawing({ - super.key, + Key? key, required this.image, - }); + }) : super(key: key); @override State createState() => _ImageEditorDrawingState(); } class _ImageEditorDrawingState extends State { + ImageItem image = ImageItem(); + Color pickerColor = Colors.white; Color currentColor = Colors.white; @@ -1666,6 +1480,7 @@ class _ImageEditorDrawingState extends State { @override void initState() { + image.load(widget.image); control.addListener(() { if (control.hasActivePath) return; @@ -1690,20 +1505,16 @@ class _ImageEditorDrawingState extends State { automaticallyImplyLeading: false, actions: [ IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: const Icon(Icons.clear), onPressed: () { Navigator.pop(context); }, - ), + ).paddingSymmetric(horizontal: 8), const Spacer(), IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: Icon( Icons.undo, - color: control.paths.isNotEmpty - ? Colors.white - : Colors.white.withAlpha(80), + color: control.paths.isNotEmpty ? white : white.withAlpha(80), ), onPressed: () { if (control.paths.isEmpty) return; @@ -1712,14 +1523,11 @@ class _ImageEditorDrawingState extends State { control.stepBack(); setState(() {}); }, - ), + ).paddingSymmetric(horizontal: 8), IconButton( - padding: const EdgeInsets.symmetric(horizontal: 8), icon: Icon( Icons.redo, - color: undoList.isNotEmpty - ? Colors.white - : Colors.white.withAlpha(80), + color: undoList.isNotEmpty ? white : white.withAlpha(80), ), onPressed: () { if (undoList.isEmpty) return; @@ -1727,33 +1535,25 @@ class _ImageEditorDrawingState extends State { control.paths.add(undoList.removeLast()); setState(() {}); }, - ), + ).paddingSymmetric(horizontal: 8), 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; + var data = await control.toImage(color: currentColor); return Navigator.pop(context, data!.buffer.asUint8List()); }, - ), + ).paddingSymmetric(horizontal: 8), ], ), body: Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, decoration: BoxDecoration( - color: currentColor == Colors.black ? Colors.white : Colors.black, + color: currentColor == black ? white : black, image: DecorationImage( - image: Image.memory(widget.image.image).image, + image: Image.memory(widget.image).image, fit: BoxFit.contain, ), ), @@ -1827,31 +1627,28 @@ class ColorButton extends StatelessWidget { final bool isSelected; const ColorButton({ - super.key, + Key? key, required this.color, required this.onTap, this.isSelected = false, - }); + }) : super(key: key); @override Widget build(BuildContext context) { - return GestureDetector( - onTap: () { - onTap(color); - }, - child: Container( - height: 34, - width: 34, - margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 23), - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: isSelected ? Colors.white : Colors.white54, - width: isSelected ? 3 : 1, - ), + return Container( + height: 34, + width: 34, + margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 23), + decoration: BoxDecoration( + color: color, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: isSelected ? Colors.white : Colors.white54, + width: isSelected ? 2 : 1, ), ), - ); + ).onTap(() { + onTap(color); + }); } } diff --git a/lib/layers/background_blur_layer.dart b/lib/layers/background_blur_layer.dart index 9334f91..b5b62f9 100755 --- a/lib/layers/background_blur_layer.dart +++ b/lib/layers/background_blur_layer.dart @@ -9,10 +9,10 @@ class BackgroundBlurLayer extends StatefulWidget { final VoidCallback? onUpdate; const BackgroundBlurLayer({ - super.key, + Key? key, required this.layerData, this.onUpdate, - }); + }) : super(key: key); @override State createState() => _BackgroundBlurLayerState(); diff --git a/lib/layers/background_layer.dart b/lib/layers/background_layer.dart index 4075606..fa6afec 100755 --- a/lib/layers/background_layer.dart +++ b/lib/layers/background_layer.dart @@ -7,10 +7,10 @@ class BackgroundLayer extends StatefulWidget { final VoidCallback? onUpdate; const BackgroundLayer({ - super.key, + Key? key, required this.layerData, this.onUpdate, - }); + }) : super(key: key); @override State createState() => _BackgroundLayerState(); diff --git a/lib/layers/emoji_layer.dart b/lib/layers/emoji_layer.dart index 402ce5f..aa79586 100755 --- a/lib/layers/emoji_layer.dart +++ b/lib/layers/emoji_layer.dart @@ -9,13 +9,13 @@ class EmojiLayer extends StatefulWidget { final VoidCallback? onUpdate; const EmojiLayer({ - super.key, + Key? key, required this.layerData, this.onUpdate, - }); + }) : super(key: key); @override - createState() => _EmojiLayerState(); + _EmojiLayerState createState() => _EmojiLayerState(); } class _EmojiLayerState extends State { diff --git a/lib/layers/image_layer.dart b/lib/layers/image_layer.dart index 14e469c..438bea2 100755 --- a/lib/layers/image_layer.dart +++ b/lib/layers/image_layer.dart @@ -9,13 +9,13 @@ class ImageLayer extends StatefulWidget { final VoidCallback? onUpdate; const ImageLayer({ - super.key, + Key? key, required this.layerData, this.onUpdate, - }); + }) : super(key: key); @override - createState() => _ImageLayerState(); + _ImageLayerState createState() => _ImageLayerState(); } class _ImageLayerState extends State { diff --git a/lib/layers/text_layer.dart b/lib/layers/text_layer.dart index b9c9f52..d194324 100755 --- a/lib/layers/text_layer.dart +++ b/lib/layers/text_layer.dart @@ -9,12 +9,12 @@ class TextLayer extends StatefulWidget { final VoidCallback? onUpdate; const TextLayer({ - super.key, + Key? key, required this.layerData, this.onUpdate, - }); + }) : super(key: key); @override - createState() => _TextViewState(); + _TextViewState createState() => _TextViewState(); } class _TextViewState extends State { diff --git a/lib/loading_screen.dart b/lib/loading_screen.dart deleted file mode 100644 index a030da5..0000000 --- a/lib/loading_screen.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:flutter/material.dart'; - -class LoadingScreen { - final GlobalKey globalKey; - - LoadingScreen(this.globalKey); - - show([String? text]) { - if (globalKey.currentContext == null) return; - - showDialog( - context: globalKey.currentContext!, - builder: (BuildContext context) => const Scaffold( - backgroundColor: Color.fromRGBO(0, 0, 0, 0), - body: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - CircularProgressIndicator( - semanticsLabel: 'Linear progress indicator', - ), - ], - ), - ), - ), - ); - } - - hide() { - if (globalKey.currentContext == null) return; - - Navigator.pop(globalKey.currentContext!); - } -} diff --git a/lib/modules/all_emojies.dart b/lib/modules/all_emojies.dart index d275204..296282a 100755 --- a/lib/modules/all_emojies.dart +++ b/lib/modules/all_emojies.dart @@ -4,80 +4,80 @@ import 'package:image_editor_plus/data/layer.dart'; import 'package:image_editor_plus/image_editor_plus.dart'; class Emojies extends StatefulWidget { - const Emojies({super.key}); + const Emojies({Key? key}) : super(key: key); @override - createState() => _EmojiesState(); + _EmojiesState createState() => _EmojiesState(); } class _EmojiesState extends State { @override Widget build(BuildContext context) { return SingleChildScrollView( - child: Container( - padding: const EdgeInsets.all(0.0), - height: 400, - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(32), - topRight: Radius.circular(32), - ), - color: Colors.black, - boxShadow: [ - BoxShadow( - blurRadius: 10.9, - color: Color.fromRGBO(0, 0, 0, 0.1), - ), - ], - ), - child: Column( - children: [ - const SizedBox(height: 16), - Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - i18n('Select Emoji'), - style: const TextStyle(color: Colors.white), - ), - ]), - const Divider(height: 1), - const SizedBox(height: 16), - Container( - height: 315, - padding: const EdgeInsets.all(0.0), - child: GridView( - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - scrollDirection: Axis.vertical, - gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: 0.0, - maxCrossAxisExtent: 60.0, - ), - children: emojis.map((String emoji) { - return GridTile( - child: GestureDetector( - onTap: () { - Navigator.pop( - context, - EmojiLayerData( - text: emoji, - size: 32.0, - ), - ); - }, - child: Container( - padding: EdgeInsets.zero, - child: Text( - emoji, - style: const TextStyle(fontSize: 35), - ), - ), - )); - }).toList(), - ), - ) - ], - ), - ), - ); + child: Container( + padding: const EdgeInsets.all(0.0), + height: 400, + decoration: const BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(32), + topRight: Radius.circular(32), + ), + color: Colors.black, + boxShadow: [ + BoxShadow( + blurRadius: 10.9, + color: Color.fromRGBO(0, 0, 0, 0.1), + ), + ], + ), + child: Column( + children: [ + const SizedBox(height: 16), + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + Text( + i18n('Select Emoji'), + style: const TextStyle(color: Colors.white), + ), + ]), + const Divider(height: 1), + const SizedBox(height: 16), + Container( + height: 315, + padding: const EdgeInsets.all(0.0), + child: GridView( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + scrollDirection: Axis.vertical, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: 0.0, + maxCrossAxisExtent: 60.0, + ), + children: emojis.map((String emoji) { + return GridTile( + child: GestureDetector( + onTap: () { + Navigator.pop( + context, + EmojiLayerData( + text: emoji, + size: 32.0, + ), + ); + }, + child: Container( + padding: EdgeInsets.zero, + child: Text( + emoji, + style: const TextStyle(fontSize: 35), + ), + ), + )); + }).toList(), + ), + ) + ], + ), + ), + ); } } diff --git a/lib/modules/color_pickers_slider.dart b/lib/modules/color_pickers_slider.dart index c09192b..d15eaa5 100755 --- a/lib/modules/color_pickers_slider.dart +++ b/lib/modules/color_pickers_slider.dart @@ -3,10 +3,10 @@ import 'package:image_editor_plus/image_editor_plus.dart'; import 'colors_picker.dart'; class ColorPickersSlider extends StatefulWidget { - const ColorPickersSlider({super.key}); + const ColorPickersSlider({Key? key}) : super(key: key); @override - createState() => _ColorPickersSliderState(); + _ColorPickersSliderState createState() => _ColorPickersSliderState(); } class _ColorPickersSliderState extends State { diff --git a/lib/modules/colors_picker.dart b/lib/modules/colors_picker.dart index fdf59cc..5744f4b 100755 --- a/lib/modules/colors_picker.dart +++ b/lib/modules/colors_picker.dart @@ -45,7 +45,7 @@ class BarColorPicker extends StatefulWidget { final Color initialColor; const BarColorPicker({ - super.key, + Key? key, this.pickMode = PickMode.color, this.horizontal = true, this.width = 200, @@ -54,10 +54,10 @@ class BarColorPicker extends StatefulWidget { this.initialColor = const Color(0xffff0000), this.thumbColor = Colors.black, required this.colorListener, - }); + }) : super(key: key); @override - createState() => _BarColorPickerState(); + _BarColorPickerState createState() => _BarColorPickerState(); } class _BarColorPickerState extends State { @@ -223,13 +223,13 @@ class CircleColorPicker extends StatefulWidget { final Color initialColor; const CircleColorPicker({ - super.key, + Key? key, this.radius = 120, this.initialColor = const Color(0xffff0000), this.thumbColor = Colors.black, this.thumbRadius = 8, required this.colorListener, - }); + }) : super(key: key); @override State createState() { diff --git a/lib/modules/emoji_layer_overlay.dart b/lib/modules/emoji_layer_overlay.dart index a6ff3fc..0b6b0c6 100755 --- a/lib/modules/emoji_layer_overlay.dart +++ b/lib/modules/emoji_layer_overlay.dart @@ -8,14 +8,14 @@ class EmojiLayerOverlay extends StatefulWidget { final Function onUpdate; const EmojiLayerOverlay({ - super.key, + Key? key, required this.layer, required this.index, required this.onUpdate, - }); + }) : super(key: key); @override - createState() => _EmojiLayerOverlayState(); + _EmojiLayerOverlayState createState() => _EmojiLayerOverlayState(); } class _EmojiLayerOverlayState extends State { diff --git a/lib/modules/image_layer_overlay.dart b/lib/modules/image_layer_overlay.dart index 7f1e00d..537eb74 100755 --- a/lib/modules/image_layer_overlay.dart +++ b/lib/modules/image_layer_overlay.dart @@ -8,14 +8,14 @@ class ImageLayerOverlay extends StatefulWidget { final Function onUpdate; const ImageLayerOverlay({ - super.key, + Key? key, required this.layerData, required this.index, required this.onUpdate, - }); + }) : super(key: key); @override - createState() => _ImageLayerOverlayState(); + _ImageLayerOverlayState createState() => _ImageLayerOverlayState(); } class _ImageLayerOverlayState extends State { diff --git a/lib/modules/text.dart b/lib/modules/text.dart index aa0bf0c..e442cc3 100755 --- a/lib/modules/text.dart +++ b/lib/modules/text.dart @@ -6,10 +6,10 @@ import 'package:image_editor_plus/image_editor_plus.dart'; import 'colors_picker.dart'; class TextEditorImage extends StatefulWidget { - const TextEditorImage({super.key}); + const TextEditorImage({Key? key}) : super(key: key); @override - createState() => _TextEditorImageState(); + _TextEditorImageState createState() => _TextEditorImageState(); } class _TextEditorImageState extends State { @@ -87,11 +87,11 @@ class _TextEditorImageState extends State { height: size.height / 2.2, child: TextField( controller: name, - decoration: InputDecoration( + decoration: const InputDecoration( border: InputBorder.none, - contentPadding: const EdgeInsets.all(10), - hintText: i18n('Insert Your Message'), - hintStyle: const TextStyle(color: Colors.white), + contentPadding: EdgeInsets.all(10), + hintText: 'Insert Your Message', + hintStyle: TextStyle(color: Colors.white), alignLabelWithHint: true, ), scrollPadding: const EdgeInsets.all(20.0), diff --git a/lib/modules/text_layer_overlay.dart b/lib/modules/text_layer_overlay.dart index 940017f..b36ef8a 100755 --- a/lib/modules/text_layer_overlay.dart +++ b/lib/modules/text_layer_overlay.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:image_editor_plus/data/layer.dart'; +import 'package:nb_utils/nb_utils.dart'; import 'package:image_editor_plus/image_editor_plus.dart'; import 'colors_picker.dart'; @@ -9,14 +10,14 @@ class TextLayerOverlay extends StatefulWidget { final Function onUpdate; const TextLayerOverlay({ - super.key, + Key? key, required this.layer, required this.index, required this.onUpdate, - }); + }) : super(key: key); @override - createState() => _TextLayerOverlayState(); + _TextLayerOverlayState createState() => _TextLayerOverlayState(); } class _TextLayerOverlayState extends State { @@ -76,13 +77,8 @@ class _TextLayerOverlayState extends State { child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), - Container( - padding: const EdgeInsets.only(left: 16), - child: Text( - i18n('Color'), - style: const TextStyle(color: Colors.white), - ), - ), + Text(i18n('Color'), style: const TextStyle(color: Colors.white)) + .paddingLeft(16), Row(children: [ const SizedBox(width: 8), Expanded( @@ -113,13 +109,9 @@ class _TextLayerOverlayState extends State { 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), - ), - ), + Text(i18n('Background Color'), + style: const TextStyle(color: Colors.white)) + .paddingLeft(16), Row(children: [ const SizedBox(width: 8), Expanded( @@ -152,13 +144,10 @@ class _TextLayerOverlayState extends State { 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), - ), - ), + Text( + i18n('Background Opacity'), + style: const TextStyle(color: Colors.white), + ).paddingLeft(16), Row(children: [ const SizedBox(width: 8), Expanded( diff --git a/lib/utils.dart b/lib/utils.dart index ebcede9..504477b 100644 --- a/lib/utils.dart +++ b/lib/utils.dart @@ -1,67 +1,58 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter_image_compress/flutter_image_compress.dart'; +import 'dart:io'; -var _formatMap = { - 'jpeg': CompressFormat.jpeg, - 'jpg': CompressFormat.jpeg, - 'heic': CompressFormat.heic, - 'png': CompressFormat.png, - 'webp': CompressFormat.webp, -}; +import 'package:flutter/foundation.dart'; +import 'package:image_compression_flutter/image_compression_flutter.dart'; class ImageUtils { - static Future convert( - image, { + static Future convert( + InputImageType image, { String format = 'jpeg', int quality = 80, - int? height, - int? width, - bool preserveExif = true, }) async { - if (!_formatMap.containsKey(format)) { - throw Exception('Output format not supported by library.'); + Uint8List imageBytes; + + if (InputImageType is Uint8List) { + imageBytes = image as Uint8List; + } else if (InputImageType is String) { + imageBytes = File(image as String).readAsBytesSync(); + } else { + throw Exception('Image must be a Uint8List or path.'); } - if (image is Uint8List) { - var output = await FlutterImageCompress.compressWithList( - image, - quality: quality, - format: _formatMap[format]!, - minHeight: height ?? 1080, - minWidth: width ?? 1920, - keepExif: preserveExif, - ); + var formatMap = { + 'jpeg': ImageOutputType.jpg, + 'jpg': ImageOutputType.jpg, + 'png': ImageOutputType.png, + 'webp|jpg': ImageOutputType.webpThenJpg, + 'webp|png': ImageOutputType.webpThenPng, + }; - return output; - } else if (image is String) { - var output = await FlutterImageCompress.compressWithFile( - image, - quality: quality, - format: _formatMap[format]!, - minHeight: height ?? 1080, - minWidth: width ?? 1920, - keepExif: preserveExif, - ); + var input = ImageFile( + filePath: 'temp.jpg', + rawBytes: imageBytes, + ); - if (output == null) { - throw Exception('Unable to compress image file'); - } + var config = Configuration( + outputType: formatMap[format]!, + useJpgPngNativeCompressor: true, + quality: quality, + ); - return output; - } else { - throw Exception('Image must be a Uint8List or path.'); - } + final param = ImageFileConfiguration(input: input, config: config); + final output = await compressor.compress(param); + + return output.rawBytes; } - static Future> convertAll( - List images, { + static Future> convertAll( + List images, { String format = 'jpeg', int quality = 80, }) async { List outputs = []; for (var image in images) { - outputs.add(await convert( + outputs.add(await convert( image, format: format, quality: quality, @@ -71,39 +62,3 @@ class ImageUtils { return outputs; } } - -class AspectRatioOption { - final String title; - final double? ratio; - - const AspectRatioOption({ - required this.title, - this.ratio, - }); -} - -class ImageEditorFeatures { - final bool crop, - text, - brush, - flip, - rotate, - blur, - filters, - emoji, - pickFromGallery, - captureFromCamera; - - const ImageEditorFeatures({ - this.pickFromGallery = false, - this.captureFromCamera = false, - this.crop = false, - this.blur = false, - this.brush = false, - this.emoji = false, - this.filters = false, - this.flip = false, - this.rotate = false, - this.text = false, - }); -} diff --git a/pubspec.lock b/pubspec.lock index 625967a..417af3b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.7" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" async: dependency: transitive description: @@ -45,10 +53,18 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" + collision: + dependency: transitive + description: + name: collision + sha256: "2bd2eb6a9dfc69bc9d92cb3401dcfadb3b8429a261102ec0e59a91c0f5fcab25" + url: "https://pub.dev" + source: hosted + version: "0.0.3" colorfilter_generator: dependency: "direct main" description: @@ -57,6 +73,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.8" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: b74247fad72c171381dbe700ca17da24deac637ab6d43c343b42867acb95c991 + url: "https://pub.dev" + source: hosted + version: "3.0.6" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.dev" + source: hosted + version: "1.2.4" convert: dependency: transitive description: @@ -65,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + crop: + dependency: "direct main" + description: + name: crop + sha256: "9d94ec70fb2a5b1f4c30a686db561ed2395a900e5b17f44a0111f2c70ecf6889" + url: "https://pub.dev" + source: hosted + version: "0.5.5" cross_file: dependency: transitive description: @@ -89,22 +129,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" + dbus: + dependency: transitive + description: + name: dbus + sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263" + url: "https://pub.dev" + source: hosted + version: "0.7.8" extended_image: dependency: "direct main" description: name: extended_image - sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767 + sha256: a6b738d9b8d5513be72c545cc3e9c5c451fbee77c8db3cbec7c32ae85b82fb93 url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "6.4.1" extended_image_library: dependency: transitive description: name: extended_image_library - sha256: bb8d08c504ebc73d476ec1c99451a61f12e95538869e734fc4f55a3a2d5c98ec + sha256: "8bf87c0b14dcb59200c923a9a3952304e4732a0901e40811428834ef39018ee1" url: "https://pub.dev" source: hosted - version: "3.5.3" + version: "3.6.0" fake_async: dependency: transitive description: @@ -117,10 +165,10 @@ packages: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.1.0" file: dependency: transitive description: @@ -141,10 +189,10 @@ packages: dependency: transitive description: name: file_selector_macos - sha256: "7a6f1ae6107265664f3f7f89a66074882c4d506aef1441c9af313c1f7e6f41ce" + sha256: "4ada532862917bf16e3adb3891fe3a5917a58bae03293e497082203a80909412" url: "https://pub.dev" source: hosted - version: "0.9.3" + version: "0.9.3+1" file_selector_platform_interface: dependency: transitive description: @@ -175,37 +223,13 @@ packages: source: hosted version: "1.0.3" flutter_image_compress: - dependency: "direct main" - description: - name: flutter_image_compress - sha256: "2babae2c69ee4849c3d3ae0f1f10c14a6b8132390e4583c5d3b1f02e8167a022" - url: "https://pub.dev" - source: hosted - version: "2.0.3" - flutter_image_compress_common: - dependency: transitive - description: - name: flutter_image_compress_common - sha256: "88aae2219cd4507992643f19aee7882fe8ff82375ffa8cb4c876e3bfe3e7c3b6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - flutter_image_compress_platform_interface: dependency: transitive description: - name: flutter_image_compress_platform_interface - sha256: dae0a3eb1fb7f38cf327cc2005dc287bc891becdd83c519277de4415fd9e065d - url: "https://pub.dev" - source: hosted - version: "1.0.1" - flutter_image_compress_web: - dependency: transitive - description: - name: flutter_image_compress_web - sha256: "677f02509bdf5fd71afb560a22f0444e82c9ee887d223cd006cb44fd145fcb17" + name: flutter_image_compress + sha256: "37f1b26399098e5f97b74c1483f534855e7dff68ead6ddaccf747029fb03f29f" url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "1.1.3" flutter_lints: dependency: "direct dev" description: @@ -222,6 +246,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.15" + flutter_svg: + dependency: transitive + description: + name: flutter_svg + sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338" + url: "https://pub.dev" + source: hosted + version: "2.0.7" flutter_test: dependency: "direct dev" description: flutter @@ -232,6 +264,14 @@ packages: description: flutter source: sdk version: "0.0.0" + fluttertoast: + dependency: transitive + description: + name: fluttertoast + sha256: "474f7d506230897a3cd28c965ec21c5328ae5605fc9c400cd330e9e9d6ac175c" + url: "https://pub.dev" + source: hosted + version: "8.2.2" font_awesome_flutter: dependency: "direct main" description: @@ -244,10 +284,10 @@ packages: dependency: "direct main" description: name: hand_signature - sha256: "69cc5a978a5a15dfc1fabb01c097efcf91e9af2006475e48bb8f2560db368a97" + sha256: bb9498cbe786c6c9d80d999e4e463477506b5cc28cf4ea7a85a4c100d38ab15d url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "2.3.0+1" http: dependency: transitive description: @@ -276,10 +316,26 @@ packages: dependency: "direct main" description: name: image - sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + image_compression: + dependency: transitive + description: + name: image_compression + sha256: "911ae4a59196ebcc33c70a38bbc1fa0e2d07243589803dd616120e1a6125bfe9" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + image_compression_flutter: + dependency: "direct main" + description: + name: image_compression_flutter + sha256: b6229024cd32c50c14c1718e32c7d434956ce21646d792467e3e1b3a1f9eac54 url: "https://pub.dev" source: hosted - version: "4.0.17" + version: "1.0.2" image_editor: dependency: "direct main" description: @@ -308,18 +364,18 @@ packages: dependency: "direct main" description: name: image_picker - sha256: "6296e98782726d37f59663f0727d0e978eee1ced1ffed45ccaba591786a7f7b3" + sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "0.8.9" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: d2bab152deb2547ea6f53d82ebca9b7e77386bb706e5789e815d37e08ea475bb + sha256: "8179b54039b50eee561676232304f487602e2950ffb3e8995ed9034d6505ca34" url: "https://pub.dev" source: hosted - version: "0.8.7+3" + version: "0.8.7+4" image_picker_for_web: dependency: transitive description: @@ -332,10 +388,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: b3e2f21feb28b24dd73a35d7ad6e83f568337c70afab5eabac876e23803f264b + sha256: bee3b7c7e6266a37fb1bfdc275bc60427029d447205d44933aac130fbb9d3330 url: "https://pub.dev" source: hosted - version: "0.8.8" + version: "0.8.8+1" image_picker_linux: dependency: transitive description: @@ -356,10 +412,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: "7c7b96bb9413a9c28229e717e6fd1e3edd1cc5569c1778fcca060ecf729b65ee" + sha256: c1134543ae2187e85299996d21c526b2f403854994026d575ae4cf30d7bb2a32 url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "2.9.0" image_picker_windows: dependency: transitive description: @@ -388,18 +444,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" matrix2d: dependency: transitive description: @@ -424,6 +480,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + nb_utils: + dependency: "direct main" + description: + name: nb_utils + sha256: c0b0ad53014c121d6ceffeb50b780d328e4a2eb9763978b875e0fd2afa915396 + url: "https://pub.dev" + source: hosted + version: "4.6.25" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" path: dependency: transitive description: @@ -432,54 +504,102 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" - path_provider: + path_parsing: dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider: + dependency: "direct main" description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.0" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" + sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8" url: "https://pub.dev" source: hosted - version: "2.0.27" + version: "2.1.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" + sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 + sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3 url: "https://pub.dev" source: hosted - version: "2.1.11" + version: "2.2.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84 url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.0" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" + sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da + url: "https://pub.dev" + source: hosted + version: "2.2.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "63e5216aae014a72fe9579ccd027323395ce7a98271d9defa9d57320d001af81" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "10.4.3" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "2ffaf52a21f64ac9b35fe7369bb9533edbd4f698e5604db8645b1064ff4cf221" + url: "https://pub.dev" + source: hosted + version: "10.3.3" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" + url: "https://pub.dev" + source: hosted + version: "9.1.4" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "7c6b1500385dd1d2ca61bb89e2488ca178e274a69144d26bbd65e33eae7c02a9" + url: "https://pub.dev" + source: hosted + version: "3.11.3" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 + url: "https://pub.dev" + source: hosted + version: "0.1.3" petitparser: dependency: transitive description: @@ -492,18 +612,18 @@ packages: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "57c07bf82207aee366dfaa3867b3164e4f03a238a461a11b0e8a3a510d51203d" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" pointycastle: dependency: transitive description: @@ -512,22 +632,70 @@ packages: url: "https://pub.dev" source: hosted version: "3.7.3" - process: + screenshot: + dependency: "direct main" + description: + name: screenshot + sha256: "30bb9fade6eb2578a1fc2e84f6b184141fc86883cda10988d4500ff00eb728e2" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + shared_preferences: dependency: transitive description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + name: shared_preferences + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" url: "https://pub.dev" source: hosted - version: "4.2.4" - screenshot: - dependency: "direct main" + version: "2.2.0" + shared_preferences_android: + dependency: transitive description: - name: screenshot - sha256: "455284ff1f5b911d94a43c25e1385485cf6b4f288293eba68f15dad711c7b81c" + name: shared_preferences_android + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d + url: "https://pub.dev" + source: hosted + version: "2.3.0" sky_engine: dependency: transitive description: flutter @@ -537,10 +705,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" stack_trace: dependency: transitive description: @@ -577,10 +745,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" typed_data: dependency: transitive description: @@ -589,6 +757,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f" + url: "https://pub.dev" + source: hosted + version: "1.1.7" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f" + url: "https://pub.dev" + source: hosted + version: "1.1.7" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e" + url: "https://pub.dev" + source: hosted + version: "1.1.7" vector_math: dependency: transitive description: @@ -597,22 +789,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" win32: dependency: transitive description: name: win32 - sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee + sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" url: "https://pub.dev" source: hosted - version: "5.0.5" + version: "5.0.7" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.2" xml: dependency: transitive description: @@ -621,6 +821,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.3.0" + zoom_widget: + dependency: "direct main" + description: + name: zoom_widget + sha256: "50fbaa460ffc938ca14c0077f8c9e5968c437897242d7f552dacff1bf3270225" + url: "https://pub.dev" + source: hosted + version: "2.0.1" sdks: - dart: ">=3.0.0 <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.1.0-185.0.dev <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 57fdf62..839b453 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,11 @@ name: image_editor_plus description: Image Editor Plugin with filters, drawing, text and emoji like stories. -version: 0.2.5 +version: 0.1.8 homepage: https://ensorta.com repository: https://github.com/hsbijarniya/image_editor_plus environment: - sdk: ">=2.17.3 <4.0.0" + sdk: ">=2.15.1 <3.0.0" flutter: ">=1.17.0" dependencies: @@ -14,16 +14,21 @@ dependencies: flutter_web_plugins: sdk: flutter cupertino_icons: ^1.0.5 + zoom_widget: ^2.0.0 font_awesome_flutter: ^10.1.0 - image_picker: ^1.0.0 - screenshot: ^2.1.0 + image_picker: ^0.8.5+3 + path_provider: ^2.0.11 + permission_handler: ^10.0.0 + screenshot: ^1.2.3 flutter_colorpicker: ^1.0.3 - extended_image: ^8.0.2 - image: ^4.0.15 + nb_utils: ^4.6.15 + extended_image: ^6.2.1 + crop: ^0.5.2 + image: ^3.2.0 image_editor: ^1.0.2 colorfilter_generator: ^0.0.8 - hand_signature: ^3.0.0 - flutter_image_compress: ^2.0.3 + hand_signature: ^2.3.0+1 + image_compression_flutter: ^1.0.2 dev_dependencies: flutter_test: