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

Navigation history does not clear even after popping the page #646

Open
jeslinjacob1995 opened this issue Nov 1, 2023 · 7 comments
Open

Comments

@jeslinjacob1995
Copy link

jeslinjacob1995 commented Nov 1, 2023

Describe the bug
Navigation history does not clear even after popping the page . If I pop from one page it will navigate correctly , but if i press browser back button it will take me to same page which i already popped

Beamer version: (e.g. v0.14.1, master, ...)
beamer: ^1.5.6

To Reproduce
Steps to reproduce the behavior:

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

import 'account_listing_page.dart';
import 'home_page.dart';

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

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

  final routerDelegate = BeamerDelegate(
    initialPath: '/home',
    locationBuilder: RoutesLocationBuilder(
      routes: {
        '*' : (context, state, data) => const HomePage(),
        // '/account' : (context, state, data) => const AccountListingPage(),
    },
    ),
  );

  @override
  Widget build(BuildContext context) {
    return  WillPopScope(
      onWillPop: () async{
        return false;
      },
      child: MaterialApp.router(
        debugShowCheckedModeBanner: false,
        routerDelegate: routerDelegate,
        routeInformationParser: BeamerParser(),
        theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
        ),
      ),
    );
  }
}
import 'package:beamer/beamer.dart';
import 'package:example_beamer/account_locations.dart';
import 'package:flutter/material.dart';

import 'account_details.dart';
import 'account_listing_page.dart';


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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  int selectedIndex = 0;
  final key = GlobalKey<BeamerState>();

  final routeDelegates = [
      BeamerDelegate(
          // initialPath: 'account',
          locationBuilder: (routeInfo,_){
          return AccountLocations(routeInfo);
      },


      ),
      BeamerDelegate(locationBuilder: (routeInfo,_){
        return AccountLocations(routeInfo);
      })
  ];



  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
              width: 500,
              height: MediaQuery.of(context).size.height,
              color: Colors.blue,
              child: Column(
                children: [
                  ListTile(
                    title: const Text("Accounts",),
                    onTap: (){
                      setState(() {
                        selectedIndex = 0;
                      });
                    },
                    selected: selectedIndex == 0,
                  ),
                  ListTile(
                    title: const Text("Profile"),
                    onTap: (){
                      setState(() {
                        selectedIndex = 1;
                      });
                    },
                    selected: selectedIndex == 1,
                  ),
                ],
              ),
            ),
            Expanded(child: Container(
              color: Colors.white,
              child: Beamer(
                key: key,
                backButtonDispatcher: BeamerBackButtonDispatcher(
                  delegate: routeDelegates[0],
                  fallbackToBeamBack: false,
                ),
                routerDelegate: routeDelegates[0],
              ),
            ))

          ],
        ),
      ),
    );
  }
}
import 'package:beamer/beamer.dart';
import 'package:example_beamer/account_details.dart';
import 'package:example_beamer/account_listing_page.dart';
import 'package:flutter/material.dart';

class AccountLocations extends BeamLocation<BeamState>{

  AccountLocations(RouteInformation routerInformation) : super(routerInformation);

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) => [
    const BeamPage(
      key: ValueKey('/account'),
      title: 'Account Listing',
      type: BeamPageType.noTransition,
      child: AccountListingPage(),
    ),
    if(state.uri.path.contains('/details'))
    const BeamPage(
      key: ValueKey('/details'),
      title: 'Account Details',
      type: BeamPageType.noTransition,
      child: AccountDetails(),
    ),
    if(state.uri.path.contains('/statement'))
    const BeamPage(
      key: ValueKey('/statement'),
      title: 'Account Statement',
      type: BeamPageType.noTransition,
      child: AccountStatement(),
    ),
  ];

  @override
  List<Pattern> get pathPatterns => ["/account"];

}

from account statement page if i call Navigator.of(context).maybePop(); it pops to correct page , but again if i press on browser back button it will take me to account statement page

Expected behavior
I am expecting that i should not go to the page which it already popped

I am running the code from flutter web with chrome browser

@stan-at-work
Copy link
Contributor

@jeslinjacob1995 Is this still an issue, try updating to the latest beamer version, and the latest flutter version.

@stan-at-work
Copy link
Contributor

Describe the bug

Navigation history does not clear even after popping the page . If I pop from one page it will navigate correctly , but if i press browser back button it will take me to same page which i already popped

Beamer version: (e.g. v0.14.1, master, ...)

beamer: ^1.5.6

To Reproduce

Steps to reproduce the behavior:


import 'package:beamer/beamer.dart';

import 'package:example_beamer/home_location.dart';

import 'package:flutter/material.dart';



import 'account_listing_page.dart';

import 'home_page.dart';



void main() {

  runApp( MyApp());

}



class MyApp extends StatelessWidget {

   MyApp({super.key});



  final routerDelegate = BeamerDelegate(

    initialPath: '/home',

    locationBuilder: RoutesLocationBuilder(

      routes: {

        '*' : (context, state, data) => const HomePage(),

        // '/account' : (context, state, data) => const AccountListingPage(),

    },

    ),

  );



  @override

  Widget build(BuildContext context) {

    return  WillPopScope(

      onWillPop: () async{

        return false;

      },

      child: MaterialApp.router(

        debugShowCheckedModeBanner: false,

        routerDelegate: routerDelegate,

        routeInformationParser: BeamerParser(),

        theme: ThemeData(

        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),

        useMaterial3: true,

        ),

      ),

    );

  }

}


import 'package:beamer/beamer.dart';

import 'package:example_beamer/account_locations.dart';

import 'package:flutter/material.dart';



import 'account_details.dart';

import 'account_listing_page.dart';





class HomePage extends StatefulWidget {

  const HomePage({super.key});



  @override

  State<HomePage> createState() => _HomePageState();

}



class _HomePageState extends State<HomePage> {



  int selectedIndex = 0;

  final key = GlobalKey<BeamerState>();



  final routeDelegates = [

      BeamerDelegate(

          // initialPath: 'account',

          locationBuilder: (routeInfo,_){

          return AccountLocations(routeInfo);

      },





      ),

      BeamerDelegate(locationBuilder: (routeInfo,_){

        return AccountLocations(routeInfo);

      })

  ];







  @override

  Widget build(BuildContext context) {

    return Scaffold(

      body: Center(

        child: Row(

          mainAxisAlignment: MainAxisAlignment.center,

          children: <Widget>[

            Container(

              width: 500,

              height: MediaQuery.of(context).size.height,

              color: Colors.blue,

              child: Column(

                children: [

                  ListTile(

                    title: const Text("Accounts",),

                    onTap: (){

                      setState(() {

                        selectedIndex = 0;

                      });

                    },

                    selected: selectedIndex == 0,

                  ),

                  ListTile(

                    title: const Text("Profile"),

                    onTap: (){

                      setState(() {

                        selectedIndex = 1;

                      });

                    },

                    selected: selectedIndex == 1,

                  ),

                ],

              ),

            ),

            Expanded(child: Container(

              color: Colors.white,

              child: Beamer(

                key: key,

                backButtonDispatcher: BeamerBackButtonDispatcher(

                  delegate: routeDelegates[0],

                  fallbackToBeamBack: false,

                ),

                routerDelegate: routeDelegates[0],

              ),

            ))



          ],

        ),

      ),

    );

  }

}


import 'package:beamer/beamer.dart';

import 'package:example_beamer/account_details.dart';

import 'package:example_beamer/account_listing_page.dart';

import 'package:flutter/material.dart';



class AccountLocations extends BeamLocation<BeamState>{



  AccountLocations(RouteInformation routerInformation) : super(routerInformation);



  @override

  List<BeamPage> buildPages(BuildContext context, BeamState state) => [

    const BeamPage(

      key: ValueKey('/account'),

      title: 'Account Listing',

      type: BeamPageType.noTransition,

      child: AccountListingPage(),

    ),

    if(state.uri.path.contains('/details'))

    const BeamPage(

      key: ValueKey('/details'),

      title: 'Account Details',

      type: BeamPageType.noTransition,

      child: AccountDetails(),

    ),

    if(state.uri.path.contains('/statement'))

    const BeamPage(

      key: ValueKey('/statement'),

      title: 'Account Statement',

      type: BeamPageType.noTransition,

      child: AccountStatement(),

    ),

  ];



  @override

  List<Pattern> get pathPatterns => ["/account"];



}

from account statement page if i call Navigator.of(context).maybePop(); it pops to correct page , but again if i press on browser back button it will take me to account statement page

Expected behavior

I am expecting that i should not go to the page which it already popped

I am running the code from flutter web with chrome browser

Also add:

backButtonDispatcher: BeamerBackButtonDispatcher(
delegate: routerDelegate,
),

As a parameter to materialApp.router(...);

@stan-at-work
Copy link
Contributor

@jeslinjacob1995 Is this fixed ?

@TheMaverickProgrammer
Copy link

This is still happening for us in beamer 1.7.0. The history is cleared but pressing back on a web browser still takes us back to the last page we were on, but we expect a cleared history to result in a no-op for the back button.

@stan-at-work
Copy link
Contributor

This is still happening for us in beamer 1.7.0. The history is cleared but pressing back on a web browser still takes us back to the last page we were on, but we expect a cleared history to result in a no-op for the back button.

How do you clear the history?

@TheMaverickProgrammer
Copy link

TheMaverickProgrammer commented Oct 29, 2024

This is still happening for us in beamer 1.7.0. The history is cleared but pressing back on a web browser still takes us back to the last page we were on, but we expect a cleared history to result in a no-op for the back button.

How do you clear the history?

On web, we're using beamBack within a nested Beamer. beamBack has a comment claiming to remove the last entry in history. We have tried a scenario without a nested Beamer as well. We see the navigation stack is different in this scenario, but the outcome on web is exactly the same which is odd.

For instance, say I'm on page A and go to page B. If we beam back from B, then I expect B to be the last entry and so it gets removed. We then end up on A. However, from A, pressing the back arrow once more in the browser will go to back B!

We can get around this, sort of, by using beamToReplacementNamed which clears the history, but pressing back on the web browser will do nothing, when we expect to just return to page A and then stop there.

@ryanscott0515
Copy link

Here is a case with Beamer using beamBack compared to the browser's back arrow, on Chrome 129, Flutter 3.24.2, and Beamer 1.7.0:

2024-10-29.16-26-58.mp4

In this video, I call beamToNamed on some pages. I do this three times, pushing page1, page2, and page3, and then click the browser back arrow, and finally press a button which will call beamBack.

As expected, the browser back button returns me to page2, and then the subsequent beamBack leads to page1.

When I change the order of these operations, something different happens. From 00:08, starting on page1, I push page2, page3, and page4. I hover the back button for a moment, but do not press it. I click the button to beamBack, which brings me to page3, and then I click the browser back button. I expect this to bring me to page2, but instead it brings me back to page4, which had been supposedly cleared by the previous beamBack. It seems like the browser history disagrees with the history Beamer knows about.

Here is the code I used for this:

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

const int _numPages = 5;
const String _prefix = "/page";
final List<String> paths = [
  for (int i = 0; i < _numPages; i++) "$_prefix$i",
];

String _depthToNamed(int depth) {
  return paths[depth];
}

int _nameToDepth(String name) {
  return int.parse(name.split(_prefix.substring(1)).last);
}

void main() {
  Beamer.setPathUrlStrategy();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  MyApp({super.key});
  final routerDelegate = BeamerDelegate(
    initialPath: paths[0],
    locationBuilder: BeamerLocationBuilder(
      beamLocations: [
        Locations(),
      ],
    ).call,
  );

  @override
  Widget build(BuildContext context) {
    return BeamerProvider(
      routerDelegate: routerDelegate,
      child: MaterialApp.router(
        title: 'Beamer test',
        debugShowCheckedModeBanner: false,
        routerDelegate: routerDelegate,
        routeInformationParser: BeamerParser(),
        backButtonDispatcher: BeamerBackButtonDispatcher(
          delegate: routerDelegate,
          alwaysBeamBack: true,
          fallbackToBeamBack: true,
        ),
      ),
    );
  }
}

class Screen extends StatelessWidget {
  const Screen({
    super.key,
    required this.name,
    this.depth = 0,
  });

  final String name;
  final int depth;

  void _beamToNext(BuildContext context) {
    Beamer.of(context).beamToNamed(_depthToNamed(depth + 1));
  }

  void _back(BuildContext context) {
    Beamer.of(context).beamBack();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: [
          Text(name),
          if (depth + 1 < _numPages)
            MaterialButton(
              height: 60.0,
              minWidth: 60.0,
              onPressed: () => _beamToNext(context),
              child: Text("Beam to ${depth + 1}"),
            ),
          if (depth > 0)
            MaterialButton(
              height: 60.0,
              minWidth: 60.0,
              onPressed: () => _back(context),
              child: Text("Beam back to ${depth - 1}"),
            ),
        ],
      ),
    );
  }
}

class MyNamedScreen extends StatelessWidget {
  const MyNamedScreen({super.key, required this.name});

  final String name;

  @override
  Widget build(BuildContext context) {
    return Screen(
      name: name,
      depth: _nameToDepth(name),
    );
  }
}

class Locations extends BeamLocation<BeamState> {
  @override
  List<Pattern> get pathPatterns => paths;

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    return [
      for (String s in state.pathPatternSegments)
        if (pathPatterns.contains('/$s'))
          BeamPage(
            key: ValueKey(s),
            child: MyNamedScreen(
              name: s,
            ),
          )
    ];
  }
}

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

4 participants