Jonny Borges

add nav2 class

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'lang/translation_service.dart';
import 'routes/app_pages.dart';
import 'shared/logger/logger_utils.dart';
... ... @@ -25,3 +27,108 @@ class MyApp extends StatelessWidget {
);
}
}
// Navigator 2 example, WIP
// TODO: add all methods from NavigatorExtension to GetNav
// class MyApp extends StatelessWidget {
// MyApp({Key? key}) : super(key: key);
// final getNav = Get.put(
// GetNav(pages: [
// GetPage(name: '/first', page: () => First()),
// GetPage(name: '/second', page: () => Second()),
// GetPage(name: '/third', page: () => Third()),
// ]),
// );
// @override
// Widget build(BuildContext context) {
// return GetMaterialApp.router(
// debugShowCheckedModeBanner: false,
// routeInformationParser: getNav.routeInformationParser,
// routerDelegate: getNav.routerDelegate,
// );
// }
// }
// class First extends StatelessWidget {
// final GetNav getNav = Get.find();
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(
// title: Text('page one'),
// leading: IconButton(
// icon: Icon(Icons.more),
// onPressed: () {
// Get.changeTheme(
// context.isDarkMode ? ThemeData.light() : ThemeData.dark());
// },
// ),
// ),
// body: Center(
// child: Container(
// height: 300,
// width: 300,
// child: ElevatedButton(
// onPressed: () {
// getNav.toNamed('/second?id=584305');
// },
// child: Text('next screen'),
// ),
// ),
// ),
// );
// }
// }
// class Second extends StatelessWidget {
// final GetNav getNav = Get.find();
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(
// title: Text('page two ${Get.parameters["id"]}'),
// ),
// body: Center(
// child: Container(
// height: 300,
// width: 300,
// child: ElevatedButton(
// onPressed: () {
// getNav.toNamed('/third');
// },
// child: Text('next screen'),
// ),
// ),
// ),
// );
// }
// }
// class Third extends StatelessWidget {
// final GetNav getNav = Get.find();
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// backgroundColor: Colors.red,
// appBar: AppBar(
// title: Text('page three'),
// ),
// body: Center(
// child: Container(
// height: 300,
// width: 300,
// child: ElevatedButton(
// onPressed: () {
// getNav.offUntil('/first');
// },
// child: Text('go to first screen'),
// ),
// ),
// ),
// );
// }
// }
... ...
... ... @@ -30,10 +30,6 @@ dependencies:
path: ../
#get_test: ^3.13.3
dependency_overrides:
get:
path: ../
dev_dependencies:
flutter_test:
sdk: flutter
... ...
... ... @@ -936,16 +936,18 @@ you can only use widgets and widget functions here''';
predicate ?? (route) => false);
}
void registerList(List<GetPage> getPages) {
routeTree = ParseRouteTree(routes: getPages);
}
void addPages(List<GetPage>? getPages) {
if (getPages != null) {
routeTree = ParseRouteTree();
routeTree.addRoutes(getPages);
registerList(getPages);
}
}
void addPage(GetPage getPage) {
routeTree = ParseRouteTree();
// routeTree = ParseRouteTree();
routeTree.addRoute(getPage);
}
... ...
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../get_core/get_core.dart';
import '../../../get_instance/get_instance.dart';
import '../../../get_state_manager/get_state_manager.dart';
import '../../../get_state_manager/src/simple/list_notifier.dart';
import '../../../get_utils/get_utils.dart';
import '../../get_navigation.dart';
import 'root_controller.dart';
... ... @@ -313,63 +315,204 @@ class GetMaterialApp extends StatelessWidget {
));
}
class GetNavigator extends StatelessWidget {
final List<GetPage> getPages;
const GetNavigator(
{Key? key,
required this.getPages,
this.pages = const <Page<dynamic>>[],
this.onPopPage,
this.initialRoute,
this.onGenerateInitialRoutes = Navigator.defaultGenerateInitialRoutes,
this.onGenerateRoute,
this.onUnknownRoute,
this.transitionDelegate = const DefaultTransitionDelegate<dynamic>(),
this.reportsRouteUpdateToEngine = false,
this.observers = const <NavigatorObserver>[],
this.restorationScopeId,
this.unKnownRoute})
: super(key: key);
class GetInformationParser extends RouteInformationParser<GetPage> {
@override
SynchronousFuture<GetPage> parseRouteInformation(
RouteInformation routeInformation) {
if (routeInformation.location == '/') {
return SynchronousFuture(Get.routeTree.routes.first);
}
print('route location: ${routeInformation.location}');
final page = Get.routeTree.matchRoute(routeInformation.location!);
print(page.parameters);
final val = page.route!.copy(
name: routeInformation.location,
parameter: Map.from(page.parameters),
);
return SynchronousFuture(val);
}
final List<Page<dynamic>> pages;
@override
RouteInformation restoreRouteInformation(GetPage uri) {
print('restore $uri');
final GetPage? unKnownRoute;
return RouteInformation(location: uri.name);
}
}
final PopPageCallback? onPopPage;
class GetNav {
GetNav({GetDelegate? routerDelegate, required this.pages})
: routerDelegate = routerDelegate ?? GetDelegate() {
Get.registerList(pages);
Get.addKey(this.routerDelegate.navigatorKey);
}
final TransitionDelegate<dynamic> transitionDelegate;
Future<T?> toNamed<T>(String route) {
return routerDelegate.toNamed(route);
}
final String? initialRoute;
Future<T?> pushRoute<T>(
GetPage route, {
bool removeUntil = false,
bool replaceCurrent = false,
bool rebuildStack = true,
}) {
return routerDelegate.pushRoute(route,
removeUntil: removeUntil,
replaceCurrent: replaceCurrent,
rebuildStack: rebuildStack);
}
final RouteFactory? onGenerateRoute;
Future<bool> popRoute() {
return routerDelegate.popRoute();
}
final RouteFactory? onUnknownRoute;
Future<T?> offUntil<T>(String route) {
return routerDelegate.offUntil(route);
}
final List<NavigatorObserver> observers;
final GetDelegate routerDelegate;
final GetInformationParser routeInformationParser = GetInformationParser();
final List<GetPage> pages;
}
final String? restorationScopeId;
class GetDelegate extends RouterDelegate<GetPage>
with
// ignore: prefer_mixin
ListNotifier,
PopNavigatorRouterDelegateMixin<GetPage> {
final List<GetPage> routes = <GetPage>[];
static const String defaultRouteName = '/';
final GetPage? notFoundRoute;
final RouteListFactory onGenerateInitialRoutes;
final List<NavigatorObserver>? dipNavObservers;
final TransitionDelegate<dynamic>? transitionDelegate;
final bool reportsRouteUpdateToEngine;
GetDelegate(
{this.notFoundRoute, this.dipNavObservers, this.transitionDelegate});
/// Called by the [Router] at startup with the structure that the
/// [RouteInformationParser] obtained from parsing the initial route.
@override
Widget build(Object context) {
Widget build(BuildContext context) {
return Navigator(
pages: getPages,
onPopPage: onPopPage,
initialRoute: initialRoute,
onGenerateInitialRoutes: onGenerateInitialRoutes,
onGenerateRoute: onGenerateRoute,
onUnknownRoute: onUnknownRoute,
transitionDelegate: transitionDelegate,
reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
observers: observers,
restorationScopeId: restorationScopeId,
key: Get.nestedKey(key),
key: navigatorKey,
onPopPage: _onPopPage,
pages: routes.toList(),
observers: [GetObserver()],
transitionDelegate:
transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
);
}
@override
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@override
Future<void> setInitialRoutePath(GetPage configuration) async {
return pushRoute(configuration);
}
@override
Future<void> setNewRoutePath(GetPage configuration) {
routes.clear();
return pushRoute(configuration);
}
/// Called by the [Router] when it detects a route information may have
/// changed as a result of rebuild.
@override
GetPage get currentConfiguration {
final route = routes.last;
return route;
}
Future<T?> toNamed<T>(String route) {
final page = Get.routeTree.matchRoute(route);
if (page.route != null) {
return pushRoute(page.route!.copy(name: route));
} else {
return pushRoute(_notFound());
}
}
Future<T?> offUntil<T>(String route) {
final page = Get.routeTree.matchRoute(route);
if (page.route != null) {
return pushRoute(page.route!.copy(name: route), removeUntil: true);
} else {
return pushRoute(_notFound());
}
}
GetPage _notFound() {
return notFoundRoute ??
GetPage(
name: '/404',
page: () => Scaffold(
body: Text('not found'),
),
);
}
Future<T?> pushRoute<T>(
GetPage route, {
bool removeUntil = false,
bool replaceCurrent = false,
bool rebuildStack = true,
}) async {
route = route.copy(unknownRoute: _notFound());
assert(!(removeUntil && replaceCurrent),
'Only removeUntil or replaceCurrent should by true!');
if (removeUntil) {
routes.clear();
} else if (replaceCurrent && routes.isNotEmpty) {
routes.removeLast();
}
_addRoute(route);
if (rebuildStack) {
refresh();
}
}
@override
Future<bool> popRoute() {
if (routes.length > 1) {
_removePage(routes.last);
return Future.value(true);
}
return Future.value(false);
}
bool canPop() {
return routes.isNotEmpty;
}
bool _onPopPage(Route<dynamic> route, dynamic result) {
final didPop = route.didPop(result);
if (!didPop) {
return false;
}
routes.remove(route.settings);
refresh();
return true;
}
void _removePage(GetPage page) {
routes.remove(page);
refresh();
}
void _addRoute(GetPage route) {
routes.add(
route,
);
refresh();
}
void addRoutes(List<GetPage> pages) {
routes.addAll(pages);
refresh();
}
}
... ...
... ... @@ -9,7 +9,11 @@ class RouteDecoder {
}
class ParseRouteTree {
final _routes = <GetPage>[];
ParseRouteTree({
required this.routes,
});
final List<GetPage> routes;
RouteDecoder matchRoute(String name) {
final uri = Uri.parse(name);
... ... @@ -34,7 +38,7 @@ class ParseRouteTree {
}
void addRoute(GetPage route) {
_routes.add(route);
routes.add(route);
// Add Page children.
for (var page in _flattenPage(route)) {
... ... @@ -82,13 +86,13 @@ class ParseRouteTree {
opaque: origin.opaque,
parameter: origin.parameter,
popGesture: origin.popGesture,
settings: origin.settings,
// settings: origin.settings,
transitionDuration: origin.transitionDuration,
middlewares: middlewares,
);
GetPage? _findRoute(String name) {
return _routes.firstWhereOrNull(
return routes.firstWhereOrNull(
(route) => route.path.regex.hasMatch(name),
);
}
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import '../../../get_core/src/get_main.dart';
... ... @@ -6,15 +8,25 @@ import '../../get_navigation.dart';
import 'custom_transition.dart';
import 'transitions_type.dart';
@immutable
class PathDecoded {
const PathDecoded(this.regex, this.keys);
final RegExp regex;
final List<String?> keys;
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is PathDecoded &&
other.regex == regex; // && listEquals(other.keys, keys);
}
@override
int get hashCode => regex.hashCode;
}
class GetPage<T> extends Page<T> {
@override
final String name;
final GetPageBuilder page;
final bool? popGesture;
final Map<String, String>? parameter;
... ... @@ -29,7 +41,19 @@ class GetPage<T> extends Page<T> {
final CustomTransition? customTransition;
final Duration? transitionDuration;
final bool fullscreenDialog;
final RouteSettings? settings;
// @override
// final LocalKey? key;
// @override
// RouteSettings get settings => this;
@override
Object? get arguments => Get.arguments;
@override
final String name;
final List<GetPage>? children;
final List<GetMiddleware>? middlewares;
final PathDecoded path;
... ... @@ -39,7 +63,7 @@ class GetPage<T> extends Page<T> {
required this.name,
required this.page,
this.title,
this.settings,
// RouteSettings settings,
this.maintainState = true,
this.curve = Curves.linear,
this.alignment,
... ... @@ -55,7 +79,13 @@ class GetPage<T> extends Page<T> {
this.children,
this.middlewares,
this.unknownRoute,
}) : path = _nameToRegex(name);
}) : path = _nameToRegex(name),
super(
key: ValueKey(name),
name: name,
arguments: Get.arguments,
);
// settings = RouteSettings(name: name, arguments: Get.arguments);
static PathDecoded _nameToRegex(String path) {
var keys = <String?>[];
... ... @@ -96,6 +126,7 @@ class GetPage<T> extends Page<T> {
bool? fullscreenDialog,
RouteSettings? settings,
List<GetPage>? children,
GetPage? unknownRoute,
List<GetMiddleware>? middlewares,
}) {
return GetPage(
... ... @@ -114,19 +145,70 @@ class GetPage<T> extends Page<T> {
customTransition: customTransition ?? this.customTransition,
transitionDuration: transitionDuration ?? this.transitionDuration,
fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog,
settings: settings ?? this.settings,
// settings: settings ?? this.settings,
children: children ?? this.children,
unknownRoute: unknownRoute ?? this.unknownRoute,
middlewares: middlewares ?? this.middlewares,
);
}
@override
Object? get arguments => Get.arguments;
@override
Route<T> createRoute(BuildContext context) {
return PageRedirect(
RouteSettings(name: name, arguments: Get.arguments), unknownRoute)
.page<T>();
this,
unknownRoute,
).page<T>();
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is GetPage<T>) {
print(other.path.hashCode == path.hashCode);
}
return other is GetPage<T> &&
other.page.runtimeType == page.runtimeType &&
other.popGesture == popGesture &&
// mapEquals(other.parameter, parameter) &&
other.title == title &&
other.transition == transition &&
other.curve == curve &&
other.alignment == alignment &&
other.maintainState == maintainState &&
other.opaque == opaque &&
other.binding == binding &&
// listEquals(other.bindings, bindings) &&
other.customTransition == customTransition &&
other.transitionDuration == transitionDuration &&
other.fullscreenDialog == fullscreenDialog &&
other.name == name &&
// listEquals(other.children, children) &&
// listEquals(other.middlewares, middlewares) &&
other.path == path &&
other.unknownRoute == unknownRoute;
}
@override
int get hashCode {
return //page.hashCode ^
popGesture.hashCode ^
// parameter.hashCode ^
title.hashCode ^
transition.hashCode ^
curve.hashCode ^
alignment.hashCode ^
maintainState.hashCode ^
opaque.hashCode ^
binding.hashCode ^
// bindings.hashCode ^
customTransition.hashCode ^
transitionDuration.hashCode ^
fullscreenDialog.hashCode ^
name.hashCode ^
// children.hashCode ^
// middlewares.hashCode ^
path.hashCode ^
unknownRoute.hashCode;
}
}
... ...
... ... @@ -189,8 +189,7 @@ class PageRedirect {
page: route!.page,
routeName: route!.name,
parameter: route!.parameter,
settings: RouteSettings(
name: settings.name, arguments: settings.arguments),
settings: settings,
curve: route!.curve,
opaque: route!.opaque,
customTransition: route!.customTransition,
... ...
... ... @@ -5,7 +5,6 @@ import 'package:get/get_navigation/src/root/parse_route.dart';
void main() {
test('Parse Page with children', () {
final tree = ParseRouteTree();
final pageTree = GetPage(name: '/city', page: () => Container(), children: [
GetPage(name: '/home', page: () => Container(), children: [
GetPage(name: '/bed-room', page: () => Container()),
... ... @@ -20,7 +19,9 @@ void main() {
]),
]);
tree.addRoute(pageTree);
final tree = ParseRouteTree(routes: <GetPage>[pageTree]);
// tree.addRoute(pageTree);
final searchRoute = '/city/work/office/pen';
final match = tree.matchRoute(searchRoute);
expect(match, isNotNull);
... ... @@ -28,7 +29,6 @@ void main() {
});
test('Parse Page without children', () {
final tree = ParseRouteTree();
final pageTree = [
GetPage(name: '/city', page: () => Container()),
GetPage(name: '/city/home', page: () => Container()),
... ... @@ -41,9 +41,11 @@ void main() {
GetPage(name: '/city/work/meeting-room', page: () => Container()),
];
for (var p in pageTree) {
tree.addRoute(p);
}
final tree = ParseRouteTree(routes: pageTree);
// for (var p in pageTree) {
// tree.addRoute(p);
// }
final searchRoute = '/city/work/office/pen';
final match = tree.matchRoute(searchRoute);
... ...