All Projects → slovnicki → Beamer

slovnicki / Beamer

Licence: mit
A router that lets you navigate through guarded page stacks and URLs using the Navigator 2.0 API effortlessly.

Programming Languages

dart
5743 projects

Projects that are alternatives of or similar to Beamer

React Router Navigation
⛵️ A complete navigation library for React Native, React DOM and React Router
Stars: ✭ 498 (+336.84%)
Mutual labels:  router, navigator
GitHubSearch
GitHub iOS client with minimum third-party dependencies.
Stars: ✭ 34 (-70.18%)
Mutual labels:  router, navigator
Flutter thrio
flutter_thrio makes it easy and fast to add flutter to existing mobile applications, and provide a simple and consistent navigator APIs.
Stars: ✭ 717 (+528.95%)
Mutual labels:  router, navigator
Hybrid Navigation
React Native Navigation that supports seamless navigation between Native and React.
Stars: ✭ 258 (+126.32%)
Mutual labels:  router, navigator
Flouter
A router for Flutter based on Navigator 2.0 and Regexp
Stars: ✭ 43 (-62.28%)
Mutual labels:  router, navigator
Cherrytree
A flexible nested router.
Stars: ✭ 105 (-7.89%)
Mutual labels:  router
Core
UI-Router Core: Framework agnostic, State-based routing for JavaScript Single Page Apps
Stars: ✭ 112 (-1.75%)
Mutual labels:  router
Router
A simple, compact and fast router package to process HTTP requests
Stars: ✭ 102 (-10.53%)
Mutual labels:  router
Xunleikuainiaoinshell
[ 迅雷快鸟 Shell 版 ] A Shell Implementation of Kuainiao, Xunlei
Stars: ✭ 102 (-10.53%)
Mutual labels:  router
Rabbits
A router module for Android application.
Stars: ✭ 118 (+3.51%)
Mutual labels:  router
Tieguanyin
Activity Builder.
Stars: ✭ 113 (-0.88%)
Mutual labels:  router
Php Router
simple and flexible Router class for PHP. with Controllers and Middlewares support.
Stars: ✭ 111 (-2.63%)
Mutual labels:  router
Router.js
Router.js is a simple and powerful javascript library to handle routing
Stars: ✭ 107 (-6.14%)
Mutual labels:  router
Rxviper
Android micro framework for developing apps based on clean VIPER architecture.
Stars: ✭ 112 (-1.75%)
Mutual labels:  router
Cottage
Simple, fast HTTP router on koa.js.
Stars: ✭ 103 (-9.65%)
Mutual labels:  router
Alien
A lightweight and fast http router from outer space
Stars: ✭ 115 (+0.88%)
Mutual labels:  router
Routes
typed bidirectional routes for OCaml/ReasonML web applications
Stars: ✭ 102 (-10.53%)
Mutual labels:  router
Scalajs React
Facebook's React on Scala.JS
Stars: ✭ 1,524 (+1236.84%)
Mutual labels:  router
Router
🍭灵活的组件化路由框架.
Stars: ✭ 1,502 (+1217.54%)
Mutual labels:  router
Pilot
Pilot — multifunction JavaScript router.
Stars: ✭ 109 (-4.39%)
Mutual labels:  router

pub test style

GitHub commit activity GitHub open issues GitHub closed issues Licence

Discord

Buy Me A Coffee

Handle your application routing, synchronize it with browser URL and more. Beamer uses the power of Navigator 2.0 API and implements all the underlying logic for you.


Key Concepts

The key concept of Beamer is a BeamLocation which represents a stack of one or more pages whose ordering and rebuild you control within pagesBuilder.

Beaming

You will be extending BeamLocation to define your app's locations to which you can then beam to using

Beamer.of(context).beamTo(MyLocation());

// or with an extension on BuildContext
context.beamTo(MyLocation());

or beam to a specific configuration of some location;

context.beamToNamed('/books/2');

// or more explicitly
context.beamTo(
  BooksLocation(
    pathBlueprint: '/books/:bookId',
    pathParameters: {'bookId': '2'},
  ),
);

You can think of it as teleporting (beaming) to another place in your app. Similar to Navigator.of(context).pushReplacementNamed('/my-route'), but Beamer is not limited to a single page, nor to a push per se. You can define an arbitrary stack of pages that get built when you beam there. Using Beamer can feel like using many of Navigator's push/pop methods at once.

You can carry an arbitrary key/value data in a location. This can be accessed from every page and updated as you travel through a location.

context.beamToNamed(
  '/book/2',
  data: {'note': 'this is my favorite book'},
);

Updating

Once at a BeamLocation, it is preferable to update the current location instead of adding it to the beamHistory if you plan to stay at the same location. For example, for going from /books to /books/3 (which are both handled by BooksLocation);

context.updateCurrentLocation(
  pathParameters: {'bookId': '3'},
  data: {'note': 'this is not my favorite book'},
);

Note that both beaming functions (beamTo and BeamToNamed) will implicitly do this for you when you try to beam to a location which you're currently on. You can turn that off by setting BeamerRouterDelegate.preferUpdate to false.

If unsure what is your current location; context.currentBeamLocation.

Beaming Back

All BeamLocations that you visited are kept in beamHistory. Therefore, there is an ability to beam back to the previous location. For example, after spending some time on /books and /books/3, say you beam to /articles which is handled by another BeamLocation (e.g. ArticlesLocation). From there, you can get back to your previous location as it were when you left, i.e. /books/3;

context.beamBack();

Note that Beamer will remove duplicate locations from beamHistory as you go. For example, if you visit BooksLocation, ArticlesLocation and then BooksLocation again, the first instance of BooksLocation will be removed from history and beamHistory will be [ArticlesLocation,BooksLocation] instead of [BooksLocation,ArticlesLocation,BooksLocation]. You can turn that off by setting BeamerRouterDelegate.removeDuplicateHistory to false.

You can check whether you can beam back with context.canBeamBack or even inspect the location you'll be beaming back to: context.beamBackLocation.


Note that "Navigator 1.0" can be used alongside Beamer. You can easily push or pop pages with Navigator.of(context), but those will not be contributing to the URI. This is often needed when some info/helper page needs to be shown that doesn't influence the browser's URL. And of course, when using Beamer on mobile, this is a non-issue as there is no URL.

Examples

Books

Here is a recreation of books example from this article where you can learn a lot about Navigator 2.0. See Example for full application code of this example.

example-books

Advanced Books

For a step further, we add more flows to demonstrate the power of Beamer. The full code is available here.

example-advanced-books

Deep Location

You can instantly beam to a location in your app that has many pages stacked (deep linking) and then pop them one by one or simply beamBack to where you came from. The full code is available here. Note that beamBackOnPop parameter of beamTo might be useful here to override AppBar's pop with beamBack.

example-deep-location

ElevatedButton(
  onPressed: () => context.beamTo(DeepLocation('/a/b/c/d')),
  // onPressed: () => context.beamTo(DeepLocation('/a/b/c/d'), beamBackOnPop: true),
  child: Text('Beam deep'),
),

Location Builder

You can override BeamLocation.builder to provide some data to the entire location, i.e. to all of the pages. The full code is available here.

example-location-builder

// in your location implementation
@override
Widget builder(BuildContext context, Navigator navigator) {
  return MyProvider<MyObject>(
    create: (context) => MyObject(),
    child: navigator,
  );
}

Guards

You can define global guards (for example, authentication guard) or location guards that keep a specific location safe. The full code is available here.

example-guards

  • Global Guards
BeamerRouterDelegate(
  beamLocations: [
    HomeLocation(),
    LoginLocation(),
    BooksLocation(),
  ],
  guards: [
    BeamGuard(
      pathBlueprints: ['/books*'],
      check: (context, location) => AuthenticationStateProvider.of(context).isAuthenticated.value,
      beamTo: (context) => LoginLocation(),
    ),
  ],
),
  • Location (local) Guards
// in your location implementation
@override
List<BeamGuard> get guards => [
  BeamGuard(
    pathBlueprints: ['/books/*'],
    check: (context, location) => location.pathParameters['bookId'] != '2',
    showPage: forbiddenPage,
  ),
];

Beamer Widget

An example of putting Beamer(s) into the Widget tree, for example in usage with bottomNavigationBar.

example-bottom-navigation-mobile example-bottom-navigation-multiple-beamers

class MyApp extends StatelessWidget {
  final _beamerKey = GlobalKey<BeamerState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: BeamerRouteInformationParser(),
      routerDelegate: RootRouterDelegate(
        homeBuilder: (context, uri) => Scaffold(
          body: Beamer(
            key: _beamerKey,
            beamLocations: _beamLocations,
          ),
          bottomNavigationBar: BottomNavigationBarWidget(
            beamerKey: _beamerKey,
          ),
        ),
      ),
    );
  }
}
class MyAppState extends State<MyApp> {
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: IndexedStack(
          index: _currentIndex,
          children: [
            Beamer(
              beamLocations: [ArticlesLocation()],
            ),
            Container(
              color: Colors.blueAccent,
              padding: const EdgeInsets.all(32.0),
              child: Beamer(
                beamLocations: [BooksLocation()],
              ),
            ),
          ],
        ),
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _currentIndex,
          items: [
            BottomNavigationBarItem(label: 'A', icon: Icon(Icons.article)),
            BottomNavigationBarItem(label: 'B', icon: Icon(Icons.book)),
          ],
          onTap: (index) => setState(() => _currentIndex = index),
        ),
      ),
    );
  }
}

Integration with Navigation UI Packages

example-animated-rail

Usage

On Entire App

In order to use Beamer on your entire app, you must (as per official documentation) construct your *App widget with .router constructor to which (along with all your regular *App attributes) you provide

  • routerDelegate that controls (re)building of Navigator pages and
  • routeInformationParser that decides which URI corresponds to which Router state/configuration, in our case - BeamLocation.

Here you use the Beamer implementation of those - BeamerRouterDelegate and BeamerRouteInformationParser, to which you pass your BeamLocations.

class MyApp extends StatelessWidget {
  final routerDelegate = BeamerRouterDelegate(
    beamLocations: [
      HomeLocation(),
      BooksLocation(),
    ],
  );
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: routerDelegate,
      routeInformationParser: BeamerRouteInformationParser(),
      backButtonDispatcher:
          BeamerBackButtonDispatcher(delegate: routerDelegate),
    );
  }
}

Deeper in the Tree

Similar to above example, but we use RootRouterDelegate with homeBuilder (same purpose as home in MaterialApp) where we put Beamer somewhere in the tree.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routeInformationParser: BeamerRouteInformationParser(),
      routerDelegate: RootRouterDelegate(
        homeBuilder: (context, uri) => Scaffold(
          body: Beamer(
            beamLocations: _beamLocations,
          ),
          ...
        ),
      ),
      ...
    );
  }
}

General Notes

  • When extending BeamLocation, two methods need to be implemented; pathBlueprints and pagesBuilder.

    • pagesBuilder returns a stack of pages that will be built by Navigator when you beam there, and pathBlueprints is there for Beamer to decide which BeamLocation corresponds to a URL coming from browser.
    • BeamLocation takes query and path parameters from URI. The : is necessary in pathBlueprints if you might get path parameter from browser.
  • BeamPage's child is an arbitrary Widgets that represent your app screen / page.

    • key is important for Navigator to optimize rebuilds. This should be a unique value for "page state".
    • BeamPage creates MaterialPageRoute, but you can extend BeamPage and override createRoute to make your own implementation instead.

Migrating

From 0.7 to 0.8

  • rename pages to pagesBuilder in BeamLocations
  • pass beamLocations to BeamerRouterDelegate instead of BeamerRouteInformationParser. See Usage

From 0.4 to 0.5

  • instead of wrapping MaterialApp with Beamer, use *App.router()
  • String BeamLocation.pathBlueprint is now List<String> BeamLocation.pathBlueprints
  • BeamLocation.withParameters constructor is removed and all parameters are handled with 1 constructor. See example if you need super.
  • BeamPage.page is now called BeamPage.child

Help and Chat

For any problems, questions, suggestions, fun,... join us at Discord Discord

Contributing

This package is still in early stages. To see the upcoming features, check the Issue board.

If you notice any bugs not present in issues, please file a new issue. If you are willing to fix or enhance things yourself, you are very welcome to make a pull request. Before making a pull request;

  • if you wish to solve an existing issue, please let us know in issue comments first
  • if you have another enhancement in mind, create an issue for it first so we can discuss your idea

Also, you can Buy Me A Coffee to speed up the development.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].