slovnicki / beamer

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

Bug ------ !isWaitingForEnteringDecision && isWaitingForExitingDecision && isPresent #559

Open wenchaosong opened 2 years ago

wenchaosong commented 2 years ago

The latest version 1.5.2

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SpUtils.getInstance();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final routerDelegate = BeamerDelegate(
    transitionDelegate: NoAnimationTransitionDelegate(),
    guards: [
      BeamGuard(
          pathPatterns: ['/main'],
          check: (context, state) {
            return SpUtils.getString("token").isNotEmpty;
          },
          beamToNamed: (_, __) => '/login'),
      BeamGuard(
          pathPatterns: ['/login'],
          check: (context, state) {
            return SpUtils.getString("token").isEmpty;
          },
          beamToNamed: (_, __) => '/main'),
    ],
    initialPath: '/login',
    locationBuilder: (routeInformation, _) => BeamerLocation(routeInformation),
  );

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      debugShowCheckedModeBanner: false,
      title: "MerchantManagePlatform",
      routeInformationParser: BeamerParser(),
      routerDelegate: routerDelegate,
    );
  }
}

class BeamerLocation extends BeamLocation<BeamState> {
  BeamerLocation(RouteInformation routeInformation) : super(routeInformation);

  @override
  List<Pattern> get pathPatterns => ['/login', '/main'];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    return [
      if (state.uri.pathSegments.contains('login'))
        BeamPage(
          key: ValueKey('login'),
          title: 'Login',
          child: LoginPage(),
        ),
      if (state.uri.pathSegments.contains('main'))
        BeamPage(
          key: ValueKey('main'),
          title: 'Main',
          child: MainPage(),
        ),
    ];
  }
}

class LoginPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        child: Text('Login'),
        onPressed: () {
          SpUtils.putString('token', "123");
          Beamer.of(context).update();
        },
      ),
    );
  }
}

class MainPage extends StatelessWidget {
  final _beamerKey = GlobalKey<BeamerState>();
  final _routerDelegate = BeamerDelegate(
      transitionDelegate: NoAnimationTransitionDelegate(),
      locationBuilder: (routeInformation, _) {
        if (routeInformation.location!.contains('deep')) {
          return DeepLocation(routeInformation);
        }
        return HomeLocation(routeInformation);
      });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        actions: [
          PopupMenuButton<int>(
            onSelected: (index) {
              if (index == 1) {
                SpUtils.putString('token', "");
                Beamer.of(context).update();
              }
            },
            position: PopupMenuPosition.under,
            itemBuilder: (context) => [
              PopupMenuItem(
                value: 1,
                height: 50,
                child: Container(
                  alignment: Alignment.center,
                  child: Row(
                    children: [
                      Container(
                        child: Text(
                          "Logout",
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ],
            child: Container(
              width: 100,
              child: Icon(Icons.menu, size: 20, color: Colors.white),
            ),
          ),
        ],
      ),
      body: Beamer(
        key: _beamerKey,
        routerDelegate: _routerDelegate,
      ),
    );
  }
}

class HomeLocation extends BeamLocation<BeamState> {
  HomeLocation(RouteInformation routeInformation) : super(routeInformation);

  @override
  List<Pattern> get pathPatterns => ['/main/home'];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    return [
      BeamPage(
        key: ValueKey('home'),
        title: 'Home',
        child: HomePage(),
      ),
    ];
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        child: Text('To deep'),
        onPressed: () {
          Beamer.of(context).beamToNamed("/main/deep");
        },
      ),
    );
  }
}

class DeepLocation extends BeamLocation<BeamState> {
  DeepLocation(RouteInformation routeInformation) : super(routeInformation);

  @override
  List<Pattern> get pathPatterns => ['/main/deep'];

  @override
  List<BeamPage> buildPages(BuildContext context, BeamState state) {
    return [
      BeamPage(
        key: ValueKey('deep'),
        title: 'Deep',
        child: DeepPage(),
      ),
    ];
  }
}

class DeepPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('DeepBody'),
    );
  }
}

First question:

I found #220 already pointed this bug, but didn't reslove yet. And if use

  Future.delayed(const Duration(milliseconds: 500))
 .then((value) => Beamer.of(context).beamToNamed("/url"));

it is a bad experience, user must wait milliseconds.

Second question:

If go to the deep page, then click menu to loginout, nothing happened How to login out in deep location?

slovnicki commented 2 years ago

First question Unfortunately no work has been done yet into investigating #220. Do you have any additional insights into what may be a better solution?

Second question Usually, it's best to have some "authentication status notifier" somewhere above and then you can register it into updateListenable property of your top BeamerDelegate so it will call guards whenever that notifier notifies. Or, you can have your top BeamerDelegate globally accessible and manually call rootBeamerDelegate.update() (which will re-run the guards) whenever your authentication status changes.

stan-at-work commented 11 months ago

@wenchaosong @slovnicki

Test this fix https://github.com/slovnicki/beamer/issues/645

wenchaosong commented 11 months ago

@stan-at-work yes, if remove the no anim, the error disappear, but, the page change looks strange, it is not good

wenchaosong commented 11 months ago

I tried ReverseTransitionDelegate, it has the same ability to make it disappear

Sten435 commented 10 months ago

I tried ReverseTransitionDelegate, it has the same ability to make it disappear

For now its good that there is a fix the thing that needs to be fixed is in beamer. @slovnicki You need to take it from here, you got a startup from my issue 🤙

stan-at-work commented 8 months ago

@slovnicki Any update on this ?

stan-at-work commented 2 months ago

@wenchaosong There are workarrounds to fix this now. Its not pretty but it can be fixed.