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

Strange behavior when pressing the Android back button on child Beamer #631

Open
pishguy opened this issue Jul 23, 2023 · 0 comments
Open

Comments

@pishguy
Copy link

pishguy commented Jul 23, 2023

Beamer version: 1.5.6

In my application, at the beginning, I have 3 pages with the following routes:

routerDelegate = BeamerDelegate(
  initialPath: initialPath,
  locationBuilder: RoutesLocationBuilder(
    routes: {
      '/signup': (_, __, ___) => const SignupScreenWidget(),
      '/verifyCode': (_, __, ___) => const VerifyCodeRootScreenWidget(),
      '/home': (_, __, ___) => const HomeScreen(),
    },
  ),
);

Inside the Home page, I defined the following BeamLocations, and since I have another BeamLocation inside the ChefRootWidget that has its own specific links, when I go to the following path:

/home/chefMainWidget/chefStoreHomePage/chefStoreMenu

There is no problem returning to the previous page by clicking on the back icon from chefStoreMenu to chefStoreHomePage. However, after touching the back button on the phone, the return occurs again, i.e., instead of returning to chefStoreHomePage, I am directly taken to the home page, which is wrong, and the page should be displayed. Therefore, both the home and chefStoreHomePage pages have their own specific BeamLocations.

The BeamLocation of the Home page is:

class HomeScreenTab extends BeamLocation<BeamState> {
  HomeScreenTab(super.routeInformation);

  @override
  List<String> get pathPatterns => [
        '/home/chefMainWidget/:storeId',
      ];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    List<BeamPage> pages = [];
    pages.add(
      const BeamPage(
        key: ValueKey('/home'),
        type: BeamPageType.noTransition,
        child: HomeRootScreenWidget(),
      ),
    );

    if (state.uri.pathSegments.length > 1) {
      String key = '';
      Widget? screen;
      switch (state.uri.pathSegments[1]) {
        case 'chefMainWidget':
          final storeId = state.pathParameters['storeId'];
          key = '/home/chefMainWidget-$storeId-${DateTime.now()}';
          screen = storeId == null ? null : ChefRootWidget(storeId: int.tryParse(storeId));
          break;
      }
      if (screen != null) {
        pages.add(BeamPage(
          key: ValueKey(key),
          type: BeamPageType.slideRightTransition,
          child: screen,
        ));
      }
    }

    return pages;
  }
}

and ChefRootWidget class:

class ChefRootWidget extends StatefulWidget {
  final int? storeId;

  const ChefRootWidget({super.key, required this.storeId});

  @override
  State<StatefulWidget> createState() => _ChefRootWidget();
}

class _ChefRootWidget extends State<ChefRootWidget> {
  int get storeId => widget.storeId!;
  late List<BeamerDelegate> _routerDelegates;


  @override
  void initState() {
    _routerDelegates = [
      BeamerDelegate(
        initialPath: '/home/chefMainWidget/chefStoreHomePage',
        locationBuilder: (routeInformation, _) {
          if (routeInformation.uri.toString().contains('/home/chefMainWidget/chefStoreHomePage')) {
            return ChefStoreBeamer(routeInformation, storeId);
          }
          return NotFound(path: routeInformation.uri.toString());
        },
      ),
    ];
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Beamer(
        routerDelegate: _routerDelegates[0],
      ),
    );
  }
}

The BeamLocation of the chefStoreHomePage page is:

class ChefStoreBeamer extends BeamLocation<BeamState> {
  final int storeId;

  ChefStoreBeamer(super.routeInformation, this.storeId);

  @override
  List<String> get pathPatterns => [
        '/home/chefMainWidget/chefStoreHomePage/chefStoreMenu/:menuId',
      ];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    List<BeamPage> pages = [];
    pages.add(
      BeamPage(
        key: ValueKey('/home/chefMainWidget/chefStoreHomePage-$storeId-${DateTime.now()}'),
        type: BeamPageType.slideRightTransition,
        child: ChefStoreHomePageWidget(storeId: storeId),
      ),
    );
    if (state.uri.pathSegments.contains('chefStoreMenu')) {
      final menuId = state.pathParameters['menuId'];
      if (menuId != null) {
        pages.add(
          BeamPage(
            key: ValueKey('/home/chefMainWidget/chefStoreHomePage/chefStoreMenu-$menuId-${DateTime.now()}'),
            type: BeamPageType.slideRightTransition,
            child: ChefMenuWidget(menuId: int.tryParse(menuId)),
          ),
        );
      }
    }
    return pages;
  }
}

What I do is use Beamer.of(context).beamToNamed to move between pages, for example:

Beamer.of(context).beamToNamed('/home/chefMainWidget/chefStoreHomePage/chefStoreMenu/$menuId');

its a full sample code:

import 'package:beamer/beamer.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class ALocation extends BeamLocation<BeamState> {
  ALocation(super.routeInformation);

  @override
  List<String> get pathPatterns => ['/a/child-root'];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    List<BeamPage> pages = [];
    pages.add(
      const BeamPage(
        key: ValueKey('/a'),
        type: BeamPageType.noTransition,
        child: RootScreen(),
      ),
    );

    if (state.pathPatternSegments.contains('child-root')) {
      pages.add(
        const BeamPage(
          key: ValueKey('/a/child-root'),
          type: BeamPageType.noTransition,
          child: ChildScreen(),
        ),
      );
    }

    return pages;
  }
}

class RootBeamerScreen extends StatefulWidget {
  const RootBeamerScreen({super.key});

  @override
  State<RootBeamerScreen> createState() => _RootBeamerScreenState();
}

class _RootBeamerScreenState extends State<RootBeamerScreen> {
  final _routerDelegates = [
    BeamerDelegate(
      initialPath: '/a',
      locationBuilder: (routeInformation, _) {
        if (routeInformation.uri.toString().contains('/a')) {
          return ALocation(routeInformation);
        }
        return NotFound(path: routeInformation.uri.toString());
      },
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Beamer(
        routerDelegate: _routerDelegates[0],
      ),
    );
  }
}

class RootScreen extends StatelessWidget {
  const RootScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('root'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            const Padding(padding: EdgeInsets.all(4)),
            TextButton(
              onPressed: () => Beamer.of(context).beamToNamed('/a/child-root'),
              child: const Text('View child-root'),
            ),
          ],
        ),
      ),
    );
  }
}

class ChildLocation extends BeamLocation<BeamState> {
  ChildLocation(super.routeInformation);

  @override
  List<String> get pathPatterns => ['/child-root/detail'];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    List<BeamPage> pages = [];
    pages.add(
      const BeamPage(
        key: ValueKey('/child-root'),
        type: BeamPageType.noTransition,
        child: ChildDetailWidget(),
      ),
    );

    if (state.pathPatternSegments.contains('detail')) {
      pages.add(
        const BeamPage(
          key: ValueKey('/child-root/detail'),
          type: BeamPageType.noTransition,
          child: DetailScreen(),
        ),
      );
    }

    return pages;
  }
}

class DetailScreen extends StatelessWidget {
  const DetailScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('child screen')),
      body: const SizedBox(
        width: double.infinity,
        height: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text('Yooohooooooooo'),
          ],
        ),
      ),
    );
  }
}

class ChildScreen extends StatefulWidget {
  const ChildScreen({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _ChildScreen();
}

class _ChildScreen extends State<ChildScreen> {
  final _routerDelegates = [
    BeamerDelegate(
      initialPath: '/child-root',
      locationBuilder: (routeInformation, _) {
        if (routeInformation.uri.toString().contains('/child-root')) {
          return ChildLocation(routeInformation);
        }
        return NotFound(path: routeInformation.uri.toString());
      },
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Beamer(
        routerDelegate: _routerDelegates[0],
      ),
    );
  }
}

class ChildDetailWidget extends StatelessWidget {
  const ChildDetailWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('child screen')),
      body: SizedBox(
        width: double.infinity,
        height: double.infinity,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            TextButton(
              onPressed: () =>
                  Beamer.of(context).beamToNamed('/child-root/detail'),
              child: const Text('Click here'),
            ),
          ],
        ),
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  MyApp({super.key});

  final routerDelegate = BeamerDelegate(
    initialPath: '/a',
    locationBuilder: RoutesLocationBuilder(
      routes: {
        '*': (context, state, data) => const RootBeamerScreen(),
      },
    ),
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.indigo),
      routerDelegate: routerDelegate,
      routeInformationParser: BeamerParser(),
      backButtonDispatcher: BeamerBackButtonDispatcher(
        delegate: routerDelegate,
      ),
    );
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant