woltapp / wolt_modal_sheet

This package provides a responsive modal with multiple pages, motion animation for page transitions, and scrollable content within each page.
MIT License
476 stars 63 forks source link

Duplicate global key in the first screen #112

Open iyar-avital opened 9 months ago

iyar-avital commented 9 months ago

Bug report

Duplicate global key on the content on the first page from two pages when moving to the second page. image

Steps to reproduce

Steps to reproduce the behavior:

  1. Open a modal with two pages
  2. Move from the first page to the second
  3. The first page body is built twice and there is a duplicate global key exception

Expected behavior

The first page does not need to be rebuilt when moving to the second page

ulusoyca commented 9 months ago

This is a difficult problem to solve due to how the slide motion during the pagination is implemented. This happens when your main content has a widget with GlobalKey. During the pagination the main content widgets are duplicated in the Offstage widget to be able to calculate the size.

This is not something we can quickly fix, but I will keep an eye on this. What is your use case? If you need a form key or something similar that will be used to refer the entire widget tree, injecting the key with the KeyedSubtree through the decorator field would help?

iyar-avital commented 9 months ago

This is a problem for me.

I used the key inside a Form widget, when clicking on a button the validate() function invoke on this key. The validate() function belongs to FormState class, so the key must be inside the form and the solution you gave me does not help. the

In addition, I can't use Form.of instead of the key because the Form in the content of the modal and the button is located as StickyActionBar (The form does not contain the button.)

Do you have any idea for me?

tp commented 8 months ago

I ran into the same issue when re-using some (proprietary) form component widgets that had GlobalKeys to scroll them into view.

ulusoyca commented 8 months ago

Thanks @tp We are aware of this. Currently, this issue is on me and I am trying to find time to address this issue. On top of my priority list. If you want to debug and create PR, I can give you background information on the root cause.

tp commented 8 months ago

I came up with this workaround for the app I am working on, where gladly we control all child widgets of the modal:

  @override
  Widget build(BuildContext context) {
    final isOffstage =
        context.findAncestorWidgetOfExactType<Offstage>()?.offstage == true;

    return Widget(
      // Do not set the key when rendering offstage (e.g. WoltModalSheet) to avoid duplicate `GlobalKey`s
      // (This will not impact any behavior as these are only needed for scrolling on-screen widgets anyway)
      key: isOffstage ? null : fieldItem.widgetKey,
ulusoyca commented 8 months ago

Very smart workaround! I will give a shot to a more proper solution. It is nice to know that a workaround is possible.

kamami commented 6 months ago

I have the same issue, will remove the Form from the widget for now.

stanislavlysenko0912 commented 5 months ago

Any new solutions? When i use

final isOffstage = context.findAncestorWidgetOfExactType<Offstage>()?.offstage == true;

On first page i got wrong true and i cant validate forms (for example). But when change to any pages and going back, got right false.

UPD. I found solution, looks bad but works. Will be waiting maybe anyone suggest more elegant solution.


class _SignInWoltpageState extends State<SignInWoltpage> {
  bool isOffstageFromDelayedCheck = true;

  @override
  void initState() {
    super.initState();
    checkVisibilityInitially();
  }

  void checkVisibilityInitially() {
    Future.delayed(const Duration(milliseconds: 50), () {
      if (!mounted) return;

      setState(() {
        isOffstageFromDelayedCheck = context.findAncestorWidgetOfExactType<Offstage>()?.offstage ?? false;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    final isOffstageFromBuildCheck = context.findAncestorWidgetOfExactType<Offstage>()?.offstage ?? true;
    final isOffstage = isOffstageFromDelayedCheck && isOffstageFromBuildCheck;
PlaxXOnline commented 1 month ago

Is there meanwhile another Solution?