Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Custom appbar with built in functionalities #1

Closed
sergiuvintu opened this issue Jan 22, 2024 · 8 comments
Closed

Feature Request: Custom appbar with built in functionalities #1

sergiuvintu opened this issue Jan 22, 2024 · 8 comments
Labels
enhancement New feature or request

Comments

@sergiuvintu
Copy link

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?

@sergiuvintu sergiuvintu added the enhancement New feature or request label Jan 22, 2024
@hm21
Copy link
Owner

hm21 commented Jan 22, 2024

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,
                    );
                  }),
            ],
          ),
        ),
      ),
    );
  }
}

@sergiuvintu
Copy link
Author

sergiuvintu commented Jan 23, 2024

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

@hm21
Copy link
Owner

hm21 commented Jan 23, 2024

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(() {});
                                      },
                                    );
                                  },
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
        ),
      );
    });
  }
}

@sergiuvintu
Copy link
Author

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. (package:pro_image_editor/pro_image_editor_main.dart:1648:11)
E/flutter ( 4358): #8 ModalRoute.onPopInvoked (package:flutter/src/widgets/routes.dart:1574:30)
E/flutter ( 4358): #9 _RouteEntry.pop (package:flutter/src/widgets/navigator.dart:3083:11)
E/flutter ( 4358): #10 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:5251:13)
E/flutter ( 4358): #11 Navigator.pop (package:flutter/src/widgets/navigator.dart:2569:27)
E/flutter ( 4358): #12 LoadingDialog.hide (package:pro_image_editor/widgets/loading_dialog.dart:110:17)
E/flutter ( 4358): #13 ProImageEditorState.doneEditing (package:pro_image_editor/pro_image_editor_main.dart:1505:26)
E/flutter ( 4358):

@hm21
Copy link
Owner

hm21 commented Jan 23, 2024

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?

@sergiuvintu
Copy link
Author

sergiuvintu commented Jan 23, 2024

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

@hm21 hm21 closed this as completed in 2fcee2c Jan 23, 2024
@hm21
Copy link
Owner

hm21 commented Jan 23, 2024

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.

@sergiuvintu
Copy link
Author

Yes everything good now. Thank you very much for all the support and keep up the good work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants