slovnicki / beamer

A routing package built on top of Router and Navigator's pages API, supporting arbitrary nested navigation, guards and more.
MIT License
591 stars 129 forks source link

[Help/Problem] Beamer key causing issues on keyboard #641

Open Retr0sec7 opened 1 year ago

Retr0sec7 commented 1 year ago

I'm using a Nested Navigation in my home screen. I'm currently having an issue with the creation of the beamers keys which affect the bevior of the digitial keyboward. As this stackoverflow post suggests, this keys are restarting themselves, making it the keyboard to behave the following way:

https://github.com/slovnicki/beamer/assets/96405082/90fdaaba-03c3-447b-b3cb-b0ef1b94791f

This is happening in all inputs inside my home view, which are quite some. Some of the solutions in that stackoverflow posts suggests to create the beamer key as static or/and place it the state of a statefulwidget (which is undesired to me but if it's required i would take the solution), this solves the issue of the beamerkey recreating itself and keyboard is fixed as well:

https://github.com/slovnicki/beamer/assets/96405082/184498f1-ece8-4b0d-a697-565d9bc0f5b2

However, as you can see, the beamer key looses it state and route information. I tried to follow this beamer example but I hit this wall.

Notes:

Here's my Home Page:

class MobileHomeView extends StatelessWidget {
  MobileHomeView(
      {Key? key, required this.userRole, required this.routeInformation})
      : super(key: key);
  final UserRole userRole;
  final RouteInformation routeInformation;

  static final GlobalKey<ScaffoldState> _scaffoldKey =
      GlobalKey<ScaffoldState>();

  //This solves the issue, but beamkey looses it's rpute information
  static final beamerKey = GlobalKey<BeamerState>();

  Maintains route information but key keeps recreating. It's the same if I move the key inside the build method
  // final beamerKey = GlobalKey<BeamerState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      endDrawer: HomeDrawer(homeContext: context),
      appBar: AppBar(
          title: Row(
            children: [
              Image.asset(
                'assets/images/IconMoyaIntro.png',
                width: 40,
                height: 40,
              ),
              const SizedBox(
                width: 12,
              ),
              const Text('Mercaditos', style: TextStyle(fontSize: 20)),
            ],
          ),
          centerTitle: true,
          backgroundColor: Theme.of(context).primaryColor,
          actions: [
            context.watch<AppBloc>().state.userDocument!.profilePicUrl!.isEmpty
                ? Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: InkWell(
                      onTap: () {
                        _scaffoldKey.currentState!.openEndDrawer();
                      },
                      child: const CircleAvatar(
                          foregroundImage: AssetImage("assets/userIcon.png")),
                    ),
                  )
                : Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: InkWell(
                      onTap: () {
                        _scaffoldKey.currentState!.openEndDrawer();
                      },
                      child: CircleAvatar(
                          foregroundImage: NetworkImage(
                              '${context.watch<AppBloc>().state.userDocument!.profilePicUrl}')),
                    ),
                  ),
            const SizedBox(
              width: 10,
            ),
          ],
          elevation: 0),
      body: Beamer(
        key: beamerKey,
        routerDelegate: BeamerDelegate(
          locationBuilder: (routeInformation, _) {
            switch (userRole) {
              case UserRole.cashier:
                if (routeInformation.location!.contains('history')) {
                  return CashierHistoryLocation(routeInformation);
                }
                if (routeInformation.location!.contains('orders')) {
                  return CashierOrdersLocation(routeInformation);
                }
                return CatalogLocation(routeInformation);
              default:
                if (routeInformation.location!.contains('tickets')) {
                  return TicketsLocation(routeInformation);
                }
                if (routeInformation.location!.contains('movements')) {
                  return MovementsLocation(routeInformation);
                }
                if (routeInformation.location!.contains('orders')) {
                  return OrdersLocation(routeInformation);
                }
                return ManagementLocation(routeInformation);
            }
          },
        ),
      ),
      bottomNavigationBar: MobileHomeNavigationBar(
        location: routeInformation.location!,
        beamerKey: beamerKey,
        homeContext: context, // este context no se pasa
        userRole: userRole,
      ),
    );
  }
}

In case needed, the bottom sheet form:

class CreateCategoryFormDialog extends StatelessWidget {
  const CreateCategoryFormDialog({
    Key? key,
    required this.webHomeContext,
  }) : super(key: key);
  final BuildContext webHomeContext;

  @override
  Widget build(BuildContext context) {
    final TextEditingController categoryNameTextFieldController =
        TextEditingController();
    final TextEditingController categoryParentIdTextFieldController =
        TextEditingController();

    return BlocBuilder<AddCategoriesDialogCubit, AddCategoriesDialogState>(
      builder: (context, state) {
        return Dialog(
          backgroundColor: Theme.of(context).colorScheme.onPrimaryContainer,
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
          child: SizedBox(
            width: 465,
            height: 505,
            child: Padding(
              padding:
                  const EdgeInsets.symmetric(horizontal: 4.0, vertical: 6.0),
              child: SingleChildScrollView(
                physics: const RangeMaintainingScrollPhysics(),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      children: [
                        const Spacer(),
                        _CloseIconButton(addCategoriesDialogContext: context)
                      ],
                    ),
                    Align(
                      alignment: Alignment.center,
                      child: SizedBox(
                        height: 75,
                        width: 75,
                        child: Icon(Icons.addchart_rounded,
                            size: 75,
                            color: Theme.of(context).colorScheme.onPrimary),
                      ),
                    ),
                    Align(
                      alignment: Alignment.center,
                      child: Padding(
                          padding: const EdgeInsets.symmetric(vertical: 15.0),
                          child: Text(
                            LocaleKeys.createCategoryTitleForAddModal.tr(),
                            style: TextStyle(
                                fontSize: 25,
                                color: Theme.of(context).colorScheme.onPrimary,
                                fontWeight: FontWeight.w600),
                          )),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(
                          left: 20.0, right: 20.0, bottom: 15.0),
                      child: SizedBox(
                        width: 415,
                        child: _NameTextField(
                            addCategoriesDialogContext: context,
                            categoryNameTextFieldController:
                                categoryNameTextFieldController),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.only(left: 20.0),
                      child: SizedBox(
                        height: 85,
                        child: Column(
                          children: [
                            Row(
                              mainAxisAlignment: MainAxisAlignment.start,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                Text(LocaleKeys.parentCategory.tr(),
                                    style: TextStyle(
                                        color: Theme.of(context)
                                            .colorScheme
                                            .onPrimary,
                                        fontSize: 15,
                                        fontWeight: FontWeight.w600)),
                                Padding(
                                  padding: const EdgeInsets.only(
                                      left: 6.0, right: 6.0),
                                  child: _CategoryParentCheckbox(
                                      addCategoriesDialogContext: context,
                                      categoryParentIdTextFieldController:
                                          categoryParentIdTextFieldController),
                                ),
                                _CategoriesDropDown(
                                  addCategoriesDialogContext: context,
                                  categoryParentIdTextFieldController:
                                      categoryParentIdTextFieldController,
                                  categoryParent: null,
                                ),
                              ],
                            ),
                            Row(
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                Row(
                                  children: [
                                    Container(
                                        width: ResponsiveValue(context,
                                            defaultValue: 155.0,
                                            conditionalValues: [
                                          const Condition.smallerThan(
                                              breakpoint: 1200, value: 180.0),
                                          const Condition.equals(
                                              name: 'TABLET', value: 180.0),
                                          const Condition.smallerThan(
                                              name: 'DESKTOP', value: 170.0),
                                        ]).value!),
                                  ],
                                ),
                                Row(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  crossAxisAlignment: CrossAxisAlignment.center,
                                  children: [
                                    Padding(
                                      padding:
                                          const EdgeInsets.only(bottom: 2.0),
                                      child: _ErrorTextParentCategoryUnselected(
                                          addCategoriesDialogContext: context,
                                          categoryParentIdTextFieldController:
                                              categoryParentIdTextFieldController),
                                    ),
                                  ],
                                ),
                              ],
                            ),
                          ],
                        ),
                      ),
                    ),
                    Row(
                      children: [
                        Padding(
                          padding:
                              const EdgeInsets.only(left: 20.0, right: 2.0),
                          child: Text(LocaleKeys.active.tr(),
                              style: TextStyle(
                                  color:
                                      Theme.of(context).colorScheme.onPrimary,
                                  fontSize: 15,
                                  fontWeight: FontWeight.w600)),
                        ),
                        _SwitchButton(addCategoriesDialogContext: context)
                      ],
                    ),
                    _AddButton(
                      addCategoriesDialogContext: context,
                      categoryParentIdTextFieldController:
                          categoryParentIdTextFieldController,
                      webHomeContext: webHomeContext,
                    )
                  ],
                ),
              ),
            ),
          ),
        );
      },
    );
  }
}
stan-at-work commented 4 months ago

I'm using a Nested Navigation in my home screen. I'm currently having an issue with the creation of the beamers keys which affect the bevior of the digitial keyboward. As this stackoverflow post suggests, this keys are restarting themselves, making it the keyboard to behave the following way:

https://github.com/slovnicki/beamer/assets/96405082/90fdaaba-03c3-447b-b3cb-b0ef1b94791f

This is happening in all inputs inside my home view, which are quite some. Some of the solutions in that stackoverflow posts suggests to create the beamer key as static or/and place it the state of a statefulwidget (which is undesired to me but if it's required i would take the solution), this solves the issue of the beamerkey recreating itself and keyboard is fixed as well:

https://github.com/slovnicki/beamer/assets/96405082/184498f1-ece8-4b0d-a697-565d9bc0f5b2

However, as you can see, the beamer key looses it state and route information. I tried to follow this beamer example but I hit this wall.

Notes:

  • As I'm currently working with BLOC pattern you will se cubits related stuff, and also stuff missing from the example as I was not sure if their were required with bloc, an example of this is @dispose and @initState methods

  • Each of this has it's own cubit and state in a separate class/file (cubits are classes that handles all ui events logic and emit a new state to the ui).

  • There are more beamer keys created inside ManagementLocation

Here's my Home Page:


class MobileHomeView extends StatelessWidget {

  MobileHomeView(

      {Key? key, required this.userRole, required this.routeInformation})

      : super(key: key);

  final UserRole userRole;

  final RouteInformation routeInformation;

  static final GlobalKey<ScaffoldState> _scaffoldKey =

      GlobalKey<ScaffoldState>();

  //This solves the issue, but beamkey looses it's rpute information

  static final beamerKey = GlobalKey<BeamerState>();

  Maintains route information but key keeps recreating. It's the same if I move the key inside the build method

  // final beamerKey = GlobalKey<BeamerState>();

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      key: _scaffoldKey,

      endDrawer: HomeDrawer(homeContext: context),

      appBar: AppBar(

          title: Row(

            children: [

              Image.asset(

                'assets/images/IconMoyaIntro.png',

                width: 40,

                height: 40,

              ),

              const SizedBox(

                width: 12,

              ),

              const Text('Mercaditos', style: TextStyle(fontSize: 20)),

            ],

          ),

          centerTitle: true,

          backgroundColor: Theme.of(context).primaryColor,

          actions: [

            context.watch<AppBloc>().state.userDocument!.profilePicUrl!.isEmpty

                ? Padding(

                    padding: const EdgeInsets.all(8.0),

                    child: InkWell(

                      onTap: () {

                        _scaffoldKey.currentState!.openEndDrawer();

                      },

                      child: const CircleAvatar(

                          foregroundImage: AssetImage("assets/userIcon.png")),

                    ),

                  )

                : Padding(

                    padding: const EdgeInsets.all(8.0),

                    child: InkWell(

                      onTap: () {

                        _scaffoldKey.currentState!.openEndDrawer();

                      },

                      child: CircleAvatar(

                          foregroundImage: NetworkImage(

                              '${context.watch<AppBloc>().state.userDocument!.profilePicUrl}')),

                    ),

                  ),

            const SizedBox(

              width: 10,

            ),

          ],

          elevation: 0),

      body: Beamer(

        key: beamerKey,

        routerDelegate: BeamerDelegate(

          locationBuilder: (routeInformation, _) {

            switch (userRole) {

              case UserRole.cashier:

                if (routeInformation.location!.contains('history')) {

                  return CashierHistoryLocation(routeInformation);

                }

                if (routeInformation.location!.contains('orders')) {

                  return CashierOrdersLocation(routeInformation);

                }

                return CatalogLocation(routeInformation);

              default:

                if (routeInformation.location!.contains('tickets')) {

                  return TicketsLocation(routeInformation);

                }

                if (routeInformation.location!.contains('movements')) {

                  return MovementsLocation(routeInformation);

                }

                if (routeInformation.location!.contains('orders')) {

                  return OrdersLocation(routeInformation);

                }

                return ManagementLocation(routeInformation);

            }

          },

        ),

      ),

      bottomNavigationBar: MobileHomeNavigationBar(

        location: routeInformation.location!,

        beamerKey: beamerKey,

        homeContext: context, // este context no se pasa

        userRole: userRole,

      ),

    );

  }

}

In case needed, the bottom sheet form:


class CreateCategoryFormDialog extends StatelessWidget {

  const CreateCategoryFormDialog({

    Key? key,

    required this.webHomeContext,

  }) : super(key: key);

  final BuildContext webHomeContext;

  @override

  Widget build(BuildContext context) {

    final TextEditingController categoryNameTextFieldController =

        TextEditingController();

    final TextEditingController categoryParentIdTextFieldController =

        TextEditingController();

    return BlocBuilder<AddCategoriesDialogCubit, AddCategoriesDialogState>(

      builder: (context, state) {

        return Dialog(

          backgroundColor: Theme.of(context).colorScheme.onPrimaryContainer,

          shape:

              RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),

          child: SizedBox(

            width: 465,

            height: 505,

            child: Padding(

              padding:

                  const EdgeInsets.symmetric(horizontal: 4.0, vertical: 6.0),

              child: SingleChildScrollView(

                physics: const RangeMaintainingScrollPhysics(),

                child: Column(

                  crossAxisAlignment: CrossAxisAlignment.start,

                  children: [

                    Row(

                      children: [

                        const Spacer(),

                        _CloseIconButton(addCategoriesDialogContext: context)

                      ],

                    ),

                    Align(

                      alignment: Alignment.center,

                      child: SizedBox(

                        height: 75,

                        width: 75,

                        child: Icon(Icons.addchart_rounded,

                            size: 75,

                            color: Theme.of(context).colorScheme.onPrimary),

                      ),

                    ),

                    Align(

                      alignment: Alignment.center,

                      child: Padding(

                          padding: const EdgeInsets.symmetric(vertical: 15.0),

                          child: Text(

                            LocaleKeys.createCategoryTitleForAddModal.tr(),

                            style: TextStyle(

                                fontSize: 25,

                                color: Theme.of(context).colorScheme.onPrimary,

                                fontWeight: FontWeight.w600),

                          )),

                    ),

                    Padding(

                      padding: const EdgeInsets.only(

                          left: 20.0, right: 20.0, bottom: 15.0),

                      child: SizedBox(

                        width: 415,

                        child: _NameTextField(

                            addCategoriesDialogContext: context,

                            categoryNameTextFieldController:

                                categoryNameTextFieldController),

                      ),

                    ),

                    Padding(

                      padding: const EdgeInsets.only(left: 20.0),

                      child: SizedBox(

                        height: 85,

                        child: Column(

                          children: [

                            Row(

                              mainAxisAlignment: MainAxisAlignment.start,

                              crossAxisAlignment: CrossAxisAlignment.center,

                              children: [

                                Text(LocaleKeys.parentCategory.tr(),

                                    style: TextStyle(

                                        color: Theme.of(context)

                                            .colorScheme

                                            .onPrimary,

                                        fontSize: 15,

                                        fontWeight: FontWeight.w600)),

                                Padding(

                                  padding: const EdgeInsets.only(

                                      left: 6.0, right: 6.0),

                                  child: _CategoryParentCheckbox(

                                      addCategoriesDialogContext: context,

                                      categoryParentIdTextFieldController:

                                          categoryParentIdTextFieldController),

                                ),

                                _CategoriesDropDown(

                                  addCategoriesDialogContext: context,

                                  categoryParentIdTextFieldController:

                                      categoryParentIdTextFieldController,

                                  categoryParent: null,

                                ),

                              ],

                            ),

                            Row(

                              mainAxisAlignment: MainAxisAlignment.start,

                              children: [

                                Row(

                                  children: [

                                    Container(

                                        width: ResponsiveValue(context,

                                            defaultValue: 155.0,

                                            conditionalValues: [

                                          const Condition.smallerThan(

                                              breakpoint: 1200, value: 180.0),

                                          const Condition.equals(

                                              name: 'TABLET', value: 180.0),

                                          const Condition.smallerThan(

                                              name: 'DESKTOP', value: 170.0),

                                        ]).value!),

                                  ],

                                ),

                                Row(

                                  mainAxisAlignment: MainAxisAlignment.center,

                                  crossAxisAlignment: CrossAxisAlignment.center,

                                  children: [

                                    Padding(

                                      padding:

                                          const EdgeInsets.only(bottom: 2.0),

                                      child: _ErrorTextParentCategoryUnselected(

                                          addCategoriesDialogContext: context,

                                          categoryParentIdTextFieldController:

                                              categoryParentIdTextFieldController),

                                    ),

                                  ],

                                ),

                              ],

                            ),

                          ],

                        ),

                      ),

                    ),

                    Row(

                      children: [

                        Padding(

                          padding:

                              const EdgeInsets.only(left: 20.0, right: 2.0),

                          child: Text(LocaleKeys.active.tr(),

                              style: TextStyle(

                                  color:

                                      Theme.of(context).colorScheme.onPrimary,

                                  fontSize: 15,

                                  fontWeight: FontWeight.w600)),

                        ),

                        _SwitchButton(addCategoriesDialogContext: context)

                      ],

                    ),

                    _AddButton(

                      addCategoriesDialogContext: context,

                      categoryParentIdTextFieldController:

                          categoryParentIdTextFieldController,

                      webHomeContext: webHomeContext,

                    )

                  ],

                ),

              ),

            ),

          ),

        );

      },

    );

  }

}

Is this still an issue, can you verify?