hopper 1.2.0 hopper: ^1.2.0 copied to clipboard
A simple Flutter library to use Navigator 2.0
A package for using Flutter Navigator 2.0. #
Features #
- It supports deep links
- It supports passing parameters to other pages associated with the path
- It supports async calls like
await hopNamed('/setting_page')
- It supports guards
Why did I write this package? #
I had an app which I developed for a client which It used Flutter Navigator 1.0, and I needed a new package a new use case to navigate to deep links which version 1.0 does not support. Then I decided to try some package out there on pub.dev beamer which is a good package but unfortunately it did not support await beamNamed(...etc)
, so I opened a thread on github.com, and the author mentioned that this will be added (as for today is 06.feb.2022 when I'm mentioning it here in this readme, and maybe in the future as you are reading this, it's already added).
So I decided to create this package and to migrate my app to it, and also I was in a hurry to write this package in order to finish my tasks related to the job (mobile app for the client).
This package until version 1.0.0 was written in 2 days
Getting started #
Simple app with one home page #
- Add the package into your pubspec.yaml
dependencies:
flutter:
sdk: flutter
hopper: ^1.2.0
- Create your
main.dart
file and add the following code:
import 'package:counter/router/classes.dart';
import 'package:flutter/material.dart';
import 'package:hopper/hopper.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final routerDelegate = AppRouter();
final routeInformationParser = AppRouteInformationParser();
MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Flutter Demo',
routerDelegate: routerDelegate,
routeInformationParser: routeInformationParser,
);
}
}
- Create a folder (not necessary) named
router
inside thelib
folder and create a file namedclasses.dart
(you can choose any name, but then you need to import it) and add the following code:
import 'package:counter/home_page.dart';
import 'package:flutter/material.dart';
import 'package:hopper/hopper.dart';
class AppRouter extends AbstractAppRouter {
final GlobalKey<NavigatorState> navigatorKey;
static const String initialRoute = '/';
AppRouter()
: navigatorKey = GlobalKey<NavigatorState>(),
super((AbstractAppRouter appRouter) => AppNavigationManager(appRouter));
}
class AppNavigationManager extends AbstractAppNavigationManager {
final AbstractAppRouter routerDelegate;
AppNavigationManager(this.routerDelegate) : super(routerDelegate);
@override
List<AppLocation> get locations => [
HomeLocation(),
];
}
class HomeLocation extends AppLocation {
static const String route = '/';
@override
List<Pattern> get pathPatterns => [route];
@override
List<AppPage> buildPages(String path, Map<String, dynamic>? params) {
return [
const AppPage(
key: ValueKey('home'),
title: 'Home',
child: HomePage(title: 'Home Page',),
),
];
}
@override
String getRoute() {
return route;
}
}
- Add a home page (this ia a counter app page)
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<HomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<HomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
- Run the app
Guards #
The package also supports guards
class AppNavigationManager extends AbstractAppNavigationManager {
final AbstractAppRouter routerDelegate;
AppNavigationManager(this.routerDelegate) : super(routerDelegate);
@override
List<AppNavigationGuard> guards = [
AppNavigationGuard(
guardExcludePattern: r"(/project_manager_login|/technician_login|/app_settings|/device_assignment)$",
guardPattern: r"/*",
guard: (path) {
final appCubit = AppDi().appCubit();
if (appCubit.state.appToken.isEmpty &&
appCubit.state.authToken.isEmpty) {
return ProjectManagerLoginLocation();
} else if (appCubit.state.appToken.isNotEmpty &&
appCubit.state.authToken.isEmpty) {
return TechnicianLoginLocation();
} else if (appCubit.state.appToken.isEmpty &&
appCubit.state.authToken.isNotEmpty) {
return DeviceAssignmentLocation();
} else {
return null;
}
},
),
];
@override
List<AppLocation> get locations => [
ProjectManagerLoginLocation(),
DeviceAssignmentLocation(),
TechnicianLoginLocation(),
AppSettingsLocation(),
HomeLocation(),
];
}
Usage #
The package uses extension with BuildContext
, see the following examples:
You can navigate to a page by using:
* context.hopNamed('/home');
* context.hopReplacementNamed('/home');
You can pass parameters associated with the path: #
* context.hopNamed('/home', {"id": 1, "name": "John"});
Return from a page #
* context.hopBack();
* context.hopBack(result); // return a result from a page
Close a dialog window or drawer #
* Navigator.of(context).pop();
You can wait for a result from a page: #
* int code = await context.hopNamed('/get_some_code');
Additional information #
Check the exmple
folder for more examples.
You will find also deeplinks
example that shows how to jump into the deep page and get back to previous page(s).
Contribution #
You can contribute to this package in order to make add new features, fix bugs, etc.
Note #
This package is not suitable for browser based applications (By contribution it can make it possible to use it in a browser based app).