Closed sergiuvintu closed 9 months ago
It is nice to hear that you like my package. I made some changes in the code. Now it's possible to add your buttons with existing functions. Because my package doesn't use a special state management package, we have to update the widgets that are dependent on the editor in a different way. Below is a complete example of how you can archive it with StreamBuilder
. I made the example for every AppBar
where I always add one custom IconButton
.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:pro_image_editor/pro_image_editor.dart';
class Demo extends StatefulWidget {
const Demo({super.key});
@override
State<Demo> createState() => DemoState();
}
class DemoState extends State<Demo> {
final _editorKey = GlobalKey<ProImageEditorState>();
late StreamController _updateAppBarStream;
@override
void initState() {
_updateAppBarStream = StreamController.broadcast();
super.initState();
}
@override
void dispose() {
_updateAppBarStream.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ProImageEditor.network(
'https://picsum.photos/id/237/2000',
key: _editorKey,
onImageEditingComplete: (byte) async {
Navigator.pop(context);
},
onUpdateUI: () {
_updateAppBarStream.add(null);
},
configs: ProImageEditorConfigs(
customWidgets: ImageEditorCustomWidgets(
appBar: AppBar(
automaticallyImplyLeading: false,
foregroundColor: Colors.white,
backgroundColor: Colors.black,
actions: [
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Cancel',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.close),
onPressed: _editorKey.currentState?.closeEditor,
);
}),
const Spacer(),
IconButton(
tooltip: 'Custom Icon',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(
Icons.bug_report,
color: Colors.white,
),
onPressed: () {},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Undo',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: Icon(
Icons.undo,
color: _editorKey.currentState?.canUndo == true ? Colors.white : Colors.white.withAlpha(80),
),
onPressed: _editorKey.currentState?.undoAction,
);
},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Redo',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: Icon(
Icons.redo,
color: _editorKey.currentState?.canRedo == true ? Colors.white : Colors.white.withAlpha(80),
),
onPressed: _editorKey.currentState?.redoAction,
);
},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Done',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.done),
iconSize: 28,
onPressed: _editorKey.currentState?.doneEditing,
);
}),
],
),
appBarPaintingEditor: AppBar(
automaticallyImplyLeading: false,
foregroundColor: Colors.white,
backgroundColor: Colors.black,
actions: [
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.arrow_back),
onPressed: _editorKey.currentState?.paintingEditor.currentState?.close,
);
}),
const SizedBox(width: 80),
const Spacer(),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(
Icons.line_weight_rounded,
color: Colors.white,
),
onPressed: _editorKey.currentState?.paintingEditor.currentState?.openLineWeightBottomSheet,
);
}),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: Icon(
_editorKey.currentState?.paintingEditor.currentState?.fillBackground == true
? Icons.format_color_reset
: Icons.format_color_fill,
color: Colors.white,
),
onPressed: _editorKey.currentState?.paintingEditor.currentState?.toggleFill);
}),
const Spacer(),
IconButton(
tooltip: 'Custom Icon',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(
Icons.bug_report,
color: Colors.white,
),
onPressed: () {},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Undo',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: Icon(
Icons.undo,
color: _editorKey.currentState?.paintingEditor.currentState?.canUndo == true ? Colors.white : Colors.white.withAlpha(80),
),
onPressed: _editorKey.currentState?.paintingEditor.currentState?.undoAction,
);
}),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Redo',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: Icon(
Icons.redo,
color: _editorKey.currentState?.paintingEditor.currentState?.canRedo == true ? Colors.white : Colors.white.withAlpha(80),
),
onPressed: _editorKey.currentState?.paintingEditor.currentState?.redoAction,
);
}),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Done',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.done),
iconSize: 28,
onPressed: _editorKey.currentState?.paintingEditor.currentState?.done,
);
}),
],
),
appBarTextEditor: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.black,
foregroundColor: Colors.white,
actions: [
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.arrow_back),
onPressed: _editorKey.currentState?.textEditor.currentState?.close,
);
}),
const Spacer(),
IconButton(
tooltip: 'Custom Icon',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(
Icons.bug_report,
color: Colors.white,
),
onPressed: () {},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
onPressed: _editorKey.currentState?.textEditor.currentState?.toggleTextAlign,
icon: Icon(
_editorKey.currentState?.textEditor.currentState?.align == TextAlign.left
? Icons.align_horizontal_left_rounded
: _editorKey.currentState?.textEditor.currentState?.align == TextAlign.right
? Icons.align_horizontal_right_rounded
: Icons.align_horizontal_center_rounded,
),
);
}),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
onPressed: _editorKey.currentState?.textEditor.currentState?.toggleBackgroundMode,
icon: const Icon(Icons.layers_rounded),
);
}),
const Spacer(),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.done),
iconSize: 28,
onPressed: _editorKey.currentState?.textEditor.currentState?.done,
);
}),
],
),
appBarCropRotateEditor: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.black,
foregroundColor: Colors.white,
actions: [
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.arrow_back),
onPressed: _editorKey.currentState?.cropRotateEditor.currentState?.close,
);
}),
const Spacer(),
IconButton(
tooltip: 'Custom Icon',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(
Icons.bug_report,
color: Colors.white,
),
onPressed: () {},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
icon: const Icon(Icons.rotate_90_degrees_ccw_outlined),
onPressed: _editorKey.currentState?.cropRotateEditor.currentState?.rotate,
);
}),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
key: const ValueKey('pro-image-editor-aspect-ratio-btn'),
icon: const Icon(Icons.crop),
onPressed: _editorKey.currentState?.cropRotateEditor.currentState?.openAspectRatioOptions,
);
}),
const Spacer(),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.done),
iconSize: 28,
onPressed: _editorKey.currentState?.cropRotateEditor.currentState?.done,
);
}),
],
),
appBarFilterEditor: AppBar(
automaticallyImplyLeading: false,
backgroundColor: Colors.black,
foregroundColor: Colors.white,
actions: [
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.arrow_back),
onPressed: _editorKey.currentState?.filterEditor.currentState?.close,
);
}),
const Spacer(),
IconButton(
tooltip: 'Custom Icon',
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(
Icons.bug_report,
color: Colors.white,
),
onPressed: () {},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
padding: const EdgeInsets.symmetric(horizontal: 8),
icon: const Icon(Icons.done),
iconSize: 28,
onPressed: _editorKey.currentState?.filterEditor.currentState?.done,
);
}),
],
),
),
),
);
}
}
Everything working fine. Thank you very much for your prompt response. The only issue is that I get "The getter 'canRedo' isn't defined for the type 'ProImageEditorState'. Try importing the library that defines 'canRedo', correcting the name to the name of an existing getter, or defining a getter or field named 'canRedo'" and the same for undo, but otherwise it is perfect. Also, by using stream builder do you think it is possible to modify the bottombar too? I would love to give it a try
Thank you for your feedback.
I can't reproduce the issue with the canRedo
and canUndo
getters in my tests. Have you updated to the latest version? Did you encounter this error in my demo example or only in your code? Btw, it's important to ensure null safety like this:
_editorKey.currentState?.canRedo == true
Even though the value is a boolean, on the first frame, the state is null. So, to check if it's true, we need to use == true
. I understand it might seem a bit unusual, especially if you're used to languages like TypeScript or JavaScript, but in Dart, it's necessary.
To your question if it's possible to modify the BottomAppBar
:
Yes, you can do that. However, in versions before 2.2.0, this changes will only work in the main editor, not in the painting editor. To make things easier, I've already updated the code for you. I recommend updating to version 2.2.0. Below is an example of how to customize the BottomAppBar
. Just remember to keep the height of the BottomAppBar
set to kToolbarHeight
. Changing it can cause issues with the calculation of helper lines.
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:pro_image_editor/models/paint_editor/paint_bottom_bar_item.dart';
import 'package:pro_image_editor/models/theme/theme_shared_values.dart';
import 'package:pro_image_editor/pro_image_editor.dart';
import 'package:pro_image_editor/widgets/flat_icon_text_button.dart';
import 'package:pro_image_editor/widgets/pro_image_editor_desktop_mode.dart';
class Demo extends StatefulWidget {
const Demo({super.key});
@override
State<Demo> createState() => DemoState();
}
class DemoState extends State<Demo> {
final _editorKey = GlobalKey<ProImageEditorState>();
late StreamController _updateUIStream;
late ScrollController _bottomBarScrollCtrl;
@override
void initState() {
_updateUIStream = StreamController.broadcast();
_bottomBarScrollCtrl = ScrollController();
super.initState();
}
@override
void dispose() {
_updateUIStream.close();
_bottomBarScrollCtrl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
var bottomTextStyle = const TextStyle(fontSize: 10.0, color: Colors.white);
List<PaintModeBottomBarItem> paintModes = [
const PaintModeBottomBarItem(
mode: PaintModeE.freeStyle,
icon: Icons.edit,
label: 'Freestyle',
),
const PaintModeBottomBarItem(
mode: PaintModeE.arrow,
icon: Icons.arrow_right_alt_outlined,
label: 'Arrow',
),
const PaintModeBottomBarItem(
mode: PaintModeE.line,
icon: Icons.horizontal_rule,
label: 'Line',
),
const PaintModeBottomBarItem(
mode: PaintModeE.rect,
icon: Icons.crop_free,
label: 'Rectangle',
),
const PaintModeBottomBarItem(
mode: PaintModeE.circle,
icon: Icons.lens_outlined,
label: 'Circle',
),
const PaintModeBottomBarItem(
mode: PaintModeE.dashLine,
icon: Icons.power_input,
label: 'Dash line',
),
];
return LayoutBuilder(builder: (context, constraints) {
return ProImageEditor.network(
'https://picsum.photos/id/237/2000',
key: _editorKey,
onImageEditingComplete: (byte) async {},
onUpdateUI: () {
_updateUIStream.add(null);
},
configs: ProImageEditorConfigs(
customWidgets: ImageEditorCustomWidgets(
bottomNavigationBar: StreamBuilder(
stream: _updateUIStream.stream,
builder: (_, __) {
return Scrollbar(
controller: _bottomBarScrollCtrl,
scrollbarOrientation: ScrollbarOrientation.top,
thickness: isDesktop ? null : 0,
child: BottomAppBar(
/// kToolbarHeight is important that helperlines will work
height: kToolbarHeight,
color: Colors.black,
padding: EdgeInsets.zero,
child: Center(
child: SingleChildScrollView(
controller: _bottomBarScrollCtrl,
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: min(constraints.maxWidth, 500),
maxWidth: 500,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FlatIconTextButton(
label: Text('Paint', style: bottomTextStyle),
icon: const Icon(
Icons.edit_rounded,
size: 22.0,
color: Colors.white,
),
onPressed: _editorKey.currentState?.openPaintingEditor,
),
FlatIconTextButton(
label: Text('Text', style: bottomTextStyle),
icon: const Icon(
Icons.text_fields,
size: 22.0,
color: Colors.white,
),
onPressed: _editorKey.currentState?.openTextEditor,
),
FlatIconTextButton(
label: Text('My Button', style: bottomTextStyle.copyWith(color: Colors.amber)),
icon: const Icon(
Icons.new_releases_outlined,
size: 22.0,
color: Colors.amber,
),
onPressed: () {},
),
FlatIconTextButton(
label: Text('Crop/ Rotate', style: bottomTextStyle),
icon: const Icon(
Icons.crop_rotate_rounded,
size: 22.0,
color: Colors.white,
),
onPressed: _editorKey.currentState?.openCropEditor,
),
FlatIconTextButton(
label: Text('Filter', style: bottomTextStyle),
icon: const Icon(
Icons.filter,
size: 22.0,
color: Colors.white,
),
onPressed: _editorKey.currentState?.openFilterEditor,
),
FlatIconTextButton(
label: Text('Emoji', style: bottomTextStyle),
icon: const Icon(
Icons.sentiment_satisfied_alt_rounded,
size: 22.0,
color: Colors.white,
),
onPressed: _editorKey.currentState?.openEmojiEditor,
),
/* Be careful with the sticker editor. It's important you add
your own logic how to load items in `stickerEditorConfigs`.
FlatIconTextButton(
key: const ValueKey('open-sticker-editor-btn'),
label: Text('Sticker', style: bottomTextStyle),
icon: const Icon(
Icons.layers_outlined,
size: 22.0,
color: Colors.white,
),
onPressed: _editorKey.currentState?.openStickerEditor,
), */
],
),
),
),
),
),
),
);
}),
bottomBarPaintingEditor: StreamBuilder(
stream: _updateUIStream.stream,
builder: (_, __) {
return Scrollbar(
controller: _bottomBarScrollCtrl,
scrollbarOrientation: ScrollbarOrientation.top,
thickness: isDesktop ? null : 0,
child: BottomAppBar(
height: kToolbarHeight,
color: Colors.black,
padding: EdgeInsets.zero,
child: Center(
child: SingleChildScrollView(
controller: _bottomBarScrollCtrl,
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: min(MediaQuery.of(context).size.width, 500),
maxWidth: 500,
),
child: Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.spaceAround,
children: <Widget>[
FlatIconTextButton(
label: Text('My Button', style: bottomTextStyle.copyWith(color: Colors.amber)),
icon: const Icon(
Icons.new_releases_outlined,
size: 22.0,
color: Colors.amber,
),
onPressed: () {},
),
...List.generate(
paintModes.length,
(index) => Builder(
builder: (_) {
var item = paintModes[index];
var color = _editorKey.currentState?.paintingEditor.currentState?.paintMode == item.mode
? imageEditorPrimaryColor
: const Color(0xFFEEEEEE);
return FlatIconTextButton(
label: Text(
item.label,
style: TextStyle(fontSize: 10.0, color: color),
),
icon: Icon(item.icon, color: color),
onPressed: () {
_editorKey.currentState?.paintingEditor.currentState?.setMode(item.mode);
setState(() {});
},
);
},
),
),
],
),
),
),
),
),
);
},
),
),
),
);
});
}
}
Yeah you were right. The getters are there after upgrading to 2.2.0. the only issue is that now I get an error when applying changes from the navigator :
E/flutter ( 4358): #5 showAdaptiveDialog (package:flutter/src/material/dialog.dart:1463:14)
E/flutter ( 4358): #6 ProImageEditorState.closeWarning (package:pro_image_editor/pro_image_editor_main.dart:1523:11)
E/flutter ( 4358): #7 ProImageEditorState.build.
Thank you for your feedback.
I'm currently unable to reproduce the issue you mentioned. Could you please share your build
method where you're using the ProImageEditor? Additionally, it would be helpful to know on which platform you encountered this issue, or if it's a problem across multiple platforms?
Sure no problem, I am currently working on Android Emulator Api version 33.
final _editor = GlobalKey<ProImageEditorState>();
late StreamController _updateAppBarStream;
@override
void initState() {
super.initState();
_updateAppBarStream = StreamController.broadcast();
cameraController.getStickers();
}
@override
void dispose() {
_updateAppBarStream.close();
super.dispose();
}
ProImageEditor.file(
File(cameraController.editAsset.value.path),
key: _editor,
onImageEditingComplete:
(Uint8List bytes) async {
final directory =
await getApplicationDocumentsDirectory();
if (!File(
"${directory.path}/${cameraController.editAsset.value.name}")
.existsSync()) {
File(directory.path +
cameraController
.editAsset.value.name)
.createSync(recursive: true);
}
File("${directory.path}/${cameraController.editAsset.value.name}")
.writeAsBytesSync(bytes);
var index = cameraController.selectedFiles
.indexWhere((element) =>
element.path ==
cameraController
.editAsset.value.path);
cameraController.selectedFiles[index] = XFile(
"${directory.path}/${cameraController.editAsset.value.name}");
cameraController.selectedFiles.refresh();
Get.back();
return;
},
configs: ProImageEditorConfigs(
activePreferredOrientations: [
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
],
i18n: const I18n(
various: I18nVarious(),
paintEditor: I18nPaintingEditor(),
textEditor: I18nTextEditor(),
cropRotateEditor: I18nCropRotateEditor(),
filterEditor: I18nFilterEditor(
filters: I18nFilters()),
emojiEditor: I18nEmojiEditor(),
stickerEditor: I18nStickerEditor(),
// More translations...
),
helperLines: const HelperLines(
showVerticalLine: true,
showHorizontalLine: true,
showRotateLine: true,
hitVibration: true,
),
customWidgets: ImageEditorCustomWidgets(
appBar: AppBar(
automaticallyImplyLeading: false,
leading: Row(children: [
GestureDetector(
child: const Icon(Icons.chevron_left,
size: 25.0, color: Colors.white),
onTap: () {
Get.back();
},
),
isImage
? const SizedBox()
: GestureDetector(
onTap: () {
var index = cameraController
.selectedFiles
.indexWhere((element) =>
element.path ==
cameraController
.editAsset
.value
.path);
cameraController.selectedFiles
.removeAt(index);
cameraController.selectedFiles
.refresh();
cameraController.fetchAssets();
Get.back();
},
child: Icon(
FluentIcons.delete_48_regular,
color: white,
size: 25,
))
]),
foregroundColor: Colors.white,
backgroundColor: dark,
actions: [
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Undo',
padding: const EdgeInsets.symmetric(
horizontal: 8),
icon: Icon(
FluentIcons.arrow_undo_48_regular,
color: _editor
.currentState
?.paintingEditor
.currentState
?.canUndo ==
true
? Colors.white
: Colors.white.withAlpha(80),
),
onPressed: _editor
.currentState?.undoAction,
);
},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Redo',
padding: const EdgeInsets.symmetric(
horizontal: 8),
icon: Icon(
FluentIcons.arrow_redo_48_regular,
color: _editor
.currentState
?.paintingEditor
.currentState
?.canRedo ==
true
? Colors.white
: Colors.white.withAlpha(80),
),
onPressed: _editor
.currentState?.redoAction,
);
},
),
StreamBuilder(
stream: _updateAppBarStream.stream,
builder: (_, __) {
return IconButton(
tooltip: 'Done',
padding:
const EdgeInsets.symmetric(
horizontal: 8),
icon: const Icon(FluentIcons
.checkmark_48_regular),
iconSize: 28,
onPressed: _editor
.currentState?.doneEditing,
);
}),
],
)),
imageEditorTheme: ImageEditorTheme(
layerHoverCursor: SystemMouseCursors.move,
helperLine: HelperLineTheme(
horizontalColor: green,
verticalColor: green,
rotateColor: red,
),
paintingEditor: const PaintingEditorTheme(),
textEditor: const TextEditorTheme(),
cropRotateEditor:
const CropRotateEditorTheme(),
filterEditor: const FilterEditorTheme(),
emojiEditor: const EmojiEditorTheme(),
stickerEditor: const StickerEditorTheme(),
background: dark,
loadingDialogTextColor: light,
uiOverlayStyle: SystemUiOverlayStyle(
statusBarColor: dark,
statusBarIconBrightness: Brightness.light,
systemNavigationBarIconBrightness:
Brightness.light,
statusBarBrightness: Brightness.dark,
systemNavigationBarColor: dark,
),
),
icons: const ImageEditorIcons(
paintingEditor: IconsPaintingEditor(
bottomNavBar:
FluentIcons.paint_bucket_24_regular,
lineWeight: FluentIcons
.line_thickness_24_regular,
freeStyle: FluentIcons.pen_48_regular,
arrow:
FluentIcons.arrow_right_48_regular,
line: FluentIcons
.line_horizontal_1_28_regular,
fill: FluentIcons.color_fill_28_filled,
noFill:
FluentIcons.color_fill_28_regular,
rectangle: FluentIcons
.rectangle_landscape_48_regular,
circle: FluentIcons.circle_48_regular,
dashLine:
FluentIcons.line_dashes_48_regular),
textEditor: IconsTextEditor(),
cropRotateEditor: IconsCropRotateEditor(),
filterEditor: IconsFilterEditor(),
emojiEditor: IconsEmojiEditor(),
stickerEditor: IconsStickerEditor(),
closeEditor:
FluentIcons.chevron_left_48_regular,
doneIcon: FluentIcons.checkmark_48_regular,
applyChanges:
FluentIcons.checkmark_48_regular,
backButton:
FluentIcons.arrow_left_48_regular,
undoAction:
FluentIcons.arrow_undo_48_regular,
redoAction:
FluentIcons.arrow_redo_48_regular,
removeElementZone:
FluentIcons.delete_48_regular,
),
paintEditorConfigs:
const PaintEditorConfigs(),
textEditorConfigs: const TextEditorConfigs(),
cropRotateEditorConfigs:
const CropRotateEditorConfigs(),
filterEditorConfigs: const FilterEditorConfigs(
// filterList: [
// ColorFilterGenerator(
// name: "CustomFilter",
// filters: [
// ColorFilterAddons.brightness(.1),
// ColorFilterAddons.contrast(.1),
// ColorFilterAddons.saturation(.15),
// ])
// ]
),
emojiEditorConfigs:
const EmojiEditorConfigs(),
stickerEditorConfigs: StickerEditorConfigs(
enabled: true,
buildStickers: (setLayer) {
return ClipRRect(
borderRadius:
const BorderRadius.vertical(
top: Radius.circular(20)),
child: Container(
color: const Color.fromARGB(
255, 224, 239, 251),
child: Obx(
() => GridView.builder(
padding:
const EdgeInsets.all(16),
gridDelegate:
const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 150,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemCount: cameraController
.stickers.length,
shrinkWrap: true,
itemBuilder: (context, index) {
Widget widget = ClipRRect(
borderRadius:
BorderRadius.circular(
7),
child: Image.network(
cameraController
.stickers[index]
.stickerImage!,
width: 120,
height: 120,
fit: BoxFit.cover,
),
);
return GestureDetector(
onTap: () =>
setLayer(widget),
child: MouseRegion(
cursor: SystemMouseCursors
.click,
child: widget,
),
);
},
),
),
));
},
),
designMode: ImageEditorDesignModeE.material,
heroTag: 'hero',
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: green,
brightness: Brightness.dark,
),
),
),
)
I did not put the whole build method as I have a lot of unrelated stuff in there. But this is the usage of the library
Thanks for sharing.
I uploaded a new version 2.2.1
which should resolve this issue. Please tell me if the issue by you still exists after you update the package.
Yes everything good now. Thank you very much for all the support and keep up the good work!
I want to thank you for this awesome package. We have the following scenario: We would like to put some custom buttons on the appbar and still have the built in functionalities.(undo,redo, apply) Is there a way we can achieve this?