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

Bug on iOS #25

Closed
Kora3 opened this issue Apr 17, 2024 · 9 comments
Closed

Bug on iOS #25

Kora3 opened this issue Apr 17, 2024 · 9 comments
Labels
bug Something isn't working

Comments

@Kora3
Copy link

Kora3 commented Apr 17, 2024

Describe the bug
There is a bug on iOS with version 2.6.2, but it works fine on Android. I was using version 2.4.3, with this version, I closed the page myself after editing by adding "Navigator.pop(context);" in the "onImageEditingComplete" function. With version 2.6.2, I had to remove the "Navigator.pop(context);" because the package already closed the page with editing on its own, and the bug seems to be caused by that. After an "onImageEditingComplete", there is this error:

======== Exception caught by animation library =====================================================
The following assertion was thrown while notifying status listeners for AnimationController:
setState() or markNeedsBuild() called during build.

This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: Overlay-[LabeledGlobalKey#e965e]
state: OverlayState#71528(tickers: tracking 0 tickers, entries: [OverlayEntry#ec0b1(opaque: false; maintainState: false), OverlayEntry#d9b02(opaque: false; maintainState: true), OverlayEntry#04268(opaque: false; maintainState: false), OverlayEntry#3731c(opaque: false; maintainState: true), OverlayEntry#19f89(opaque: false; maintainState: false), OverlayEntry#998d6(opaque: false; maintainState: true), OverlayEntry#0aac6(opaque: false; maintainState: false), OverlayEntry#acddb(opaque: false; maintainState: true)])
The widget which was currently being built when the offending call was made was: Builder
dirty
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild. (package:flutter/src/widgets/framework.dart:5042:9)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:5054:6)
#2 State.setState (package:flutter/src/widgets/framework.dart:1223:15)
#3 OverlayState._didChangeEntryOpacity (package:flutter/src/widgets/overlay.dart:792:5)
#4 OverlayEntry.opaque= (package:flutter/src/widgets/overlay.dart:113:15)
#5 TransitionRoute._handleStatusChanged (package:flutter/src/widgets/routes.dart:241:32)
#6 AnimationLocalStatusListenersMixin.notifyStatusListeners (package:flutter/src/animation/listener_helpers.dart:240:19)
#7 AnimationController._checkStatusChanged (package:flutter/src/animation/animation_controller.dart:850:7)
#8 AnimationController._startSimulation (package:flutter/src/animation/animation_controller.dart:781:5)
#9 AnimationController._animateToInternal (package:flutter/src/animation/animation_controller.dart:644:12)
#10 AnimationController.reverse (package:flutter/src/animation/animation_controller.dart:527:12)
#11 TransitionRoute.didPop (package:flutter/src/widgets/routes.dart:305:18)
#12 LocalHistoryRoute.didPop (package:flutter/src/widgets/routes.dart:757:18)
#13 _RouteEntry.handlePop (package:flutter/src/widgets/navigator.dart:3076:16)
#14 NavigatorState._flushHistoryUpdates (package:flutter/src/widgets/navigator.dart:4270:22)
#15 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:5294:7)
#16 LoadingDialog.show. (package:pro_image_editor/widgets/loading_dialog.dart:99:48)
#17 new CupertinoDialogRoute. (package:flutter/src/cupertino/route.dart:1349:25)
#18 RawDialogRoute.buildPage (package:flutter/src/widgets/routes.dart:2160:28)
#19 _ModalScopeState.build.. (package:flutter/src/widgets/routes.dart:973:53)
#20 Builder.build (package:flutter/src/widgets/basic.dart:7698:48)
#21 StatelessElement.build (package:flutter/src/widgets/framework.dart:5550:49)
#22 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5480:15)
#23 Element.rebuild (package:flutter/src/widgets/framework.dart:5196:7)
#24 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2904:19)
#25 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:989:21)
#26 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:448:5)
#27 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1386:15)
#28 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1311:9)
#29 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1169:5)
#30 _invoke (dart:ui/hooks.dart:312:13)
#31 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:399:5)
#32 _drawFrame (dart:ui/hooks.dart:283:31)
The AnimationController notifying status listeners was: AnimationController#15184(◀ 1.000; for MyPageRoute(null))

I would like to point out that on an iOS simulator, this bug poses no problem, it is just reported and the application continues to work, but when the update of my app was validated on the app store and I tried, I I realized that this was causing the application to crash.

@Kora3 Kora3 added the bug Something isn't working label Apr 17, 2024
@hm21
Copy link
Owner

hm21 commented Apr 17, 2024

Thanks for reporting this issue. Can you post for me the ProImageEditor widget with all configurations as you use it?

As example:

ProImageEditor.file(
      file,
      onImageEditingComplete: (Uint8List bytes) async {
         /// ....
      },
      configs: ProImageEditorConfigs(
         /// ....
      )
);

@Kora3
Copy link
Author

Kora3 commented Apr 17, 2024

This is it:

class ImageEditor extends StatefulWidget {
  final Uint8List uint8list;
  final void Function(Uint8List) onEdit;
  const ImageEditor({super.key, required this.uint8list, required this.onEdit});

  @override
  State<ImageEditor> createState() => _ImageEditorState();
}

class _ImageEditorState extends State<ImageEditor> {

  late List gif;

  @override
  void initState() {
    // TODO: implement initState
    gif = ListStorage().getList(gifsKey) ?? [];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: SafeArea(
        child: ProImageEditor.memory(
          widget.uint8list,
          allowCompleteWithEmptyEditing: true,
          onImageEditingComplete: (Uint8List image) async {
            widget.onEdit(image);
            // Navigator.pop(context);
          },
          configs: ProImageEditorConfigs(
            // theme: ThemeService().theme == ThemeMode.light ? AppTheme.light : AppTheme.dark,
            i18n: I18n(
              paintEditor: I18nPaintingEditor(
                bottomNavigationBarText: 'paint'.tr,
                freestyle: 'freestyle'.tr,
                arrow: 'arrow'.tr,
                line: 'line'.tr,
                rectangle: 'rectangle'.tr,
                circle: 'circle'.tr,
                dashLine: 'dash_line'.tr,
                lineWidth: 'line_width'.tr,
                toggleFill: 'toggle_fill'.tr,
                undo: 'undo'.tr,
                redo: 'redo'.tr,
                done: 'done'.tr,
                back: 'back'.tr,
                smallScreenMoreTooltip: 'more'.tr,
              ),
              textEditor: I18nTextEditor(
                bottomNavigationBarText: 'text'.tr,
                inputHintText: 'enter_text'.tr,
                back: 'back'.tr,
                done: 'done'.tr,
                textAlign: 'align_text'.tr,
                backgroundMode: 'background_mode'.tr,
                smallScreenMoreTooltip: 'more'.tr,
              ),
              cropRotateEditor: I18nCropRotateEditor(
                bottomNavigationBarText: 'crop_rotate'.tr,
                rotate: 'rotate'.tr,
                ratio: 'Ratio',
                back: 'back'.tr,
                done: 'done'.tr,
                prepareImageDialogMsg: 'please_wait'.tr,
                applyChangesDialogMsg: 'please_wait'.tr,
                smallScreenMoreTooltip: 'more'.tr,
              ),
              filterEditor: I18nFilterEditor(
                bottomNavigationBarText: 'filter'.tr,
                applyFilterDialogMsg: 'filter_applied'.tr,
                back: 'back'.tr,
                done: 'done'.tr,
              ),
              blurEditor: I18nBlurEditor(
                // applyBlurDialogMsg: ,
                // bottomNavigationBarText: ,
                back: 'back'.tr,
                done: 'done'.tr,
              ),
              emojiEditor: I18nEmojiEditor(
                bottomNavigationBarText: 'Emoji',
                search: 'search'.tr,
                noRecents: 'no_recents'.tr,
              ),
              stickerEditor: const I18nStickerEditor(
                bottomNavigationBarText: 'Stickers',
              ),
              various: I18nVarious(
                loadingDialogMsg: '${'please_wait'.tr}...',
                closeEditorWarningTitle: 'editor_warning_title'.tr,
                closeEditorWarningMessage: '',
                closeEditorWarningConfirmBtn: 'OK',
                closeEditorWarningCancelBtn: 'cancel'.tr,
              ),
              cancel: 'cancel'.tr,
              undo: 'undo'.tr,
              redo: 'redo'.tr,
              done: 'done'.tr,
              remove: 'remove'.tr,
              doneLoadingMsg: 'applying_changes'.tr,
            ),
            helperLines: const HelperLines(
              hitVibration: false,
            ),
            customWidgets: const ImageEditorCustomWidgets(),
            imageEditorTheme: const ImageEditorTheme(),
            icons: const ImageEditorIcons(),
            paintEditorConfigs: const PaintEditorConfigs(),
            textEditorConfigs: const TextEditorConfigs(),
            cropRotateEditorConfigs: const CropRotateEditorConfigs(),
            filterEditorConfigs: const FilterEditorConfigs(),
            emojiEditorConfigs: const EmojiEditorConfigs(),
            designMode: Platform.isIOS ? ImageEditorDesignModeE.cupertino : ImageEditorDesignModeE.material,
            stickerEditorConfigs: StickerEditorConfigs(
              enabled: true,
              buildStickers: (setLayer) {
                return GridView.builder(
                  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 2,
                    crossAxisSpacing: 15.0,
                    mainAxisSpacing: 15.0,
                    childAspectRatio: 1.4,
                  ),
                  padding: const EdgeInsets.all(10),
                  shrinkWrap: true,
                  itemCount: gif.length,
                  itemBuilder: (BuildContext context, int index) {
                    String gifUrl = gif[index];
                    Widget widget = ClipRRect(
                      borderRadius: BorderRadius.circular(13.0),
                      child: CacheImageDisposable(url: gifUrl),
                    );
                    return InkWell(
                      onTap: () {
                        setLayer(widget);
                      },
                      child: MouseRegion(
                        cursor: SystemMouseCursors.click,
                        child: widget,
                      ),
                    );
                  },
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}

@hm21
Copy link
Owner

hm21 commented Apr 17, 2024

Thanks for posting your code. Actually, it's still necessary to call Navigator.pop(context); inside of onImageEditingComplete.
You only don't need to pop it inside of onImageEditingComplete if you use onCloseEditor and pop the editor there. I just tested it on iOS, Android and Windows and in all cases everything works fine for me.

Anyway, my question is, I see you call widget.onEdit(image), what exactly happens there? If you are running async code there, please remember to use await. And did you call pop there?

@Kora3
Copy link
Author

Kora3 commented Apr 17, 2024

The bug occurs when designMode = ImageEditorDesignModeE.cupertino. When is ImageEditorDesignModeE.marterial, its work fine. When it ImageEditorDesignModeE.cupertino, it closes automatically without having to specify 'Navigator.pop(context);' in 'onImageEditingComplete', and it is this automatic closing which creates the bug, but when it is ImageEditorDesignModeE.marterial, it does not close, and always remains on the editing page if you do not put 'Navigator.pop( context);' in 'onImageEditingComplete'. So it's the behavior when designMode = ImageEditorDesignModeE.cupertino that causes the problem.

I used the same code with version 2.4.3 of the package and everything worked fine, it was when I updated to version 2.6.3 that the bug appeared on iOS.

@hm21
Copy link
Owner

hm21 commented Apr 17, 2024

Okay, that sounds interesting. Can I ask, does it also happen on Windows or Android when you change the design mode to Cupertino or is it required that we use iOS?

@hm21
Copy link
Owner

hm21 commented Apr 17, 2024

Okay, I found the problem, I will try to fix it now.

@Kora3
Copy link
Author

Kora3 commented Apr 17, 2024

I haven't tried it on another platform, but on iOS, it works when it's set to Cupertino.

Okay great then, good job

@hm21
Copy link
Owner

hm21 commented Apr 17, 2024

Okay, the problem was that the Flutter team changed the rendering process on iOS devices, which caused the problem that the loading-dialog tried to close twice. Anyway, I fixed it, and it should work now in version 2.6.4. Remember you have to call Navigator.pop(context) again like before. If you still have this problem, please let me know.

hm21 added a commit that referenced this issue Apr 17, 2024
…hen editing completion

This commit fixes an issue where the editor was throwing an error on iOS devices with cupertino design, when done editing. This resolves the problem described in #25.
@Kora3
Copy link
Author

Kora3 commented Apr 17, 2024

I will try it, thank you

@hm21 hm21 closed this as completed Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants