Jonny Borges

migrate to nav 2

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/route_manager.dart';
import 'lang/translation_service.dart';
import 'routes/app_pages.dart';
... ... @@ -9,12 +9,27 @@ void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late final routerDelegate = GetNavigation.instance = GetNavigation(
pages: AppPages.routes,
navigatorObservers: [GetObserver()],
);
final routeInformationParser =
NewGetInformationParser(initialRoute: AppPages.INITIAL);
@override
Widget build(BuildContext context) {
return GetMaterialApp.router(
routeInformationParser: routeInformationParser,
routerDelegate: routerDelegate,
// title: 'Router Management Example',
debugShowCheckedModeBanner: false,
enableLog: true,
logWriterCallback: Logger.write,
... ... @@ -27,6 +42,8 @@ class MyApp extends StatelessWidget {
}
}
/// Nav 2 snippet
// void main() {
// runApp(MyApp());
... ...
... ... @@ -32,10 +32,11 @@ class CountryView extends GetView<HomeController> {
itemBuilder: (context, index) {
final country = controller.state.countries[index];
return ListTile(
onTap: () {
onTap: () async {
//Get.rootDelegate.toNamed('/home/country');
Get.rootDelegate
final data = await GetNavigation.instance
.toNamed('/home/country/details?id=$index');
print(data);
},
trailing: CircleAvatar(
backgroundImage: NetworkImage(
... ...
... ... @@ -2,12 +2,14 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/home_controller.dart';
class DetailsView extends GetView<HomeController> {
@override
Widget build(BuildContext context) {
final parameter = Get.rootDelegate.parameters;
final args = ModalRoute.of(context)!.settings.arguments as PageSettings;
final parameter = args.params; //Get.rootDelegate.parameters;
final country = controller.getCountryById(parameter['id'] ?? '');
return Container(
decoration: BoxDecoration(
... ... @@ -76,6 +78,11 @@ class DetailsView extends GetView<HomeController> {
'${country.totalRecovered}',
style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
TextButton(
onPressed: () {
GetNavigation.instance.back('djsoidjsoidj');
},
child: Text('back'))
],
)),
),
... ...
... ... @@ -75,7 +75,8 @@ class HomeView extends GetView<HomeController> {
shape: StadiumBorder(),
),
onPressed: () async {
await Get.rootDelegate.toNamed('/home/country');
//await Navigation Get.rootDelegate.toNamed('/home/country');
GetNavigation.instance.toNamed('/home/country');
},
child: Text(
'fetch_country'.tr,
... ...
... ... @@ -7,6 +7,7 @@ export 'src/nav2/get_nav_config.dart';
export 'src/nav2/get_navigator.dart';
export 'src/nav2/get_router_delegate.dart';
export 'src/nav2/router_outlet.dart';
export 'src/nav3/get_navigation/index.dart';
export 'src/root/get_cupertino_app.dart';
export 'src/root/get_material_app.dart';
export 'src/root/internacionalization.dart';
... ...
... ... @@ -14,7 +14,7 @@ import 'root/parse_route.dart';
/// It replaces the Flutter Navigator, but needs no context.
/// You can to use navigator.push(YourRoute()) rather
/// Navigator.push(context, YourRoute());
NavigatorState? get navigator => GetNavigation(Get).key.currentState;
NavigatorState? get navigator => GetNavigationExt(Get).key.currentState;
extension ExtensionBottomSheet on GetInterface {
Future<T?> bottomSheet<T>(
... ... @@ -474,7 +474,7 @@ extension ExtensionSnackbar on GetInterface {
}
}
extension GetNavigation on GetInterface {
extension GetNavigationExt on GetInterface {
/// **Navigation.push()** shortcut.<br><br>
///
/// Pushes a new `page` to the stack
... ... @@ -1280,10 +1280,15 @@ extension NavTwoExt on GetInterface {
static late final _routeTree = ParseRouteTree(routes: []);
ParseRouteTree get routeTree => _routeTree;
void addPage(GetPage getPage) {
routeTree.addRoute(getPage);
}
void removePage(GetPage getPage) {
routeTree.removeRoute(getPage);
}
/// Casts the stored router delegate to a desired type
TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() =>
routerDelegate as TDelegate?;
... ...
import 'package:flutter/widgets.dart';
import '../routes/default_route.dart';
import '../routes/get_route.dart';
... ... @@ -11,6 +12,7 @@ class GetNavigator extends Navigator {
bool reportsRouteUpdateToEngine = false,
TransitionDelegate? transitionDelegate,
String? initialRoute,
String? restorationScopeId,
}) : super(
//keys should be optional
key: key,
... ... @@ -35,6 +37,7 @@ class GetNavigator extends Navigator {
}
},
reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
restorationScopeId: restorationScopeId,
pages: pages,
observers: [
// GetObserver(),
... ... @@ -52,6 +55,7 @@ class GetNavigator extends Navigator {
bool reportsRouteUpdateToEngine = false,
TransitionDelegate? transitionDelegate,
String? initialRoute,
String? restorationScopeId,
}) : super(
//keys should be optional
key: key,
... ... @@ -65,6 +69,7 @@ class GetNavigator extends Navigator {
return true;
},
reportsRouteUpdateToEngine: reportsRouteUpdateToEngine,
restorationScopeId: restorationScopeId,
pages: pages,
observers: [
// GetObserver(),
... ...
import 'dart:async';
import 'package:flutter/material.dart';
import '../../../../get.dart';
import '../../../../get_state_manager/src/simple/list_notifier.dart';
import '../url_strategy/url_strategy.dart';
class GetNavigation extends RouterDelegate<PageSettings>
with
ListNotifierSingleMixin,
PopNavigatorRouterDelegateMixin<PageSettings>,
IGetNavigation {
final _activePages = <GetPage>[];
final GetPage _unknownPage;
final List<NavigatorObserver>? navigatorObservers;
final String? restorationScopeId;
@override
final navigatorKey = GlobalKey<NavigatorState>();
static late final GetNavigation instance;
@override
Future<void> setInitialRoutePath(PageSettings configuration) async {
setNewRoutePath(configuration);
}
GetNavigation({
String? initialPage,
required List<GetPage> pages,
GetPage? unknownPage,
this.navigatorObservers,
this.restorationScopeId,
bool showHashOnUrl = false,
}) : _unknownPage = unknownPage ??
GetPage(
name: '/404',
page: () =>
Scaffold(body: Center(child: Text('Route not found'))),
) {
if (!showHashOnUrl && GetPlatform.isWeb) setUrlStrategy();
Get.addPages(pages);
Get.addPage(_unknownPage);
// setNewRoutePath(_buildPageSettings(_initialPage));
}
PageSettings _buildPageSettings(String page, [Object? data]) {
var uri = Uri.parse(page);
return PageSettings(uri, data);
}
@protected
GetPage<T>? _getPage<T>(PageSettings arguments) {
var page = arguments.uri.path;
final parameters = arguments.params;
if (parameters.isNotEmpty) {
final uri = Uri(path: page, queryParameters: parameters);
page = uri.toString();
}
final decoder = Get.routeTree.matchRoute(page, arguments: arguments);
decoder.replaceArguments(arguments);
//decoder.replaceParameters(arguments)
return decoder.route as GetPage<T>?;
}
@protected
GetPage<T> _buildSettings<T>(GetPage<T> page, PageSettings arguments) {
return page.copy(
completer: _activePages.isEmpty ? null : Completer(),
arguments: arguments);
}
Future<T?> _push<T>(PageSettings arguments, GetPage<T> page) async {
final activePage = _buildSettings<T>(page, arguments);
final onStackPage = _activePages
.firstWhereOrNull((element) => element.key == activePage.key);
/// There are no duplicate routes in the stack
if (onStackPage == null) {
_activePages.add(activePage);
} else {
/// There are duplicate routes, reorder
_activePages.remove(onStackPage);
_activePages.add(onStackPage);
}
refresh();
return activePage.completer?.future;
}
Future<T?> _replace<T>(PageSettings arguments, GetPage<T> page) async {
final index = _activePages.length > 1 ? _activePages.length - 1 : 0;
final activePage = _buildSettings<T>(page, arguments);
Get.addPage(activePage);
_activePages[index] = activePage;
refresh();
final result = await activePage.completer?.future;
Get.removePage(activePage);
return result;
}
/// Takes a route [name] String generated by [to], [off], [offAll]
/// (and similar context navigation methods), cleans the extra chars and
/// accommodates the format.
/// TODO: check for a more "appealing" URL naming convention.
/// `() => MyHomeScreenView` becomes `/my-home-screen-view`.
String _cleanRouteName(String name) {
name = name.replaceAll('() => ', '');
/// uncommonent for URL styling.
// name = name.paramCase!;
if (!name.startsWith('/')) {
name = '/$name';
}
return Uri.tryParse(name)?.toString() ?? name;
}
@protected
void _popWithResult<T>([T? result]) {
final completer = _activePages.removeLast().completer;
if (completer?.isCompleted == false) completer!.complete(result);
}
@override
Future<T?> toNamed<T>(String page, [Object? data]) async {
final arguments = _buildPageSettings(page, data);
final route = _getPage<T>(arguments);
if (route != null) {
return _push<T>(arguments, route);
}
throw 'Route $page not registered';
}
@override
Future<T?> to<T>(
Widget Function() page, {
bool? opaque,
Transition? transition,
Curve? curve,
Duration? duration,
int? id,
String? routeName,
bool fullscreenDialog = false,
dynamic arguments,
Binding? binding,
bool preventDuplicates = true,
bool? popGesture,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
}) async {
routeName = _cleanRouteName("/${page.runtimeType}");
final route = GetPage<T>(
name: routeName,
opaque: opaque ?? true,
page: page,
gestureWidth: gestureWidth,
showCupertinoParallax: showCupertinoParallax,
popGesture: popGesture ?? Get.defaultPopGesture,
transition: transition ?? Get.defaultTransition,
curve: curve ?? Get.defaultTransitionCurve,
fullscreenDialog: fullscreenDialog,
binding: binding,
transitionDuration: duration ?? Get.defaultTransitionDuration,
);
Get.addPage(route);
final args = _buildPageSettings(routeName, arguments);
final result = await _push<T>(args, route);
Get.removePage(route);
return result;
}
@override
Future<T?> off<T>(
Widget Function() page, {
bool? opaque,
Transition? transition,
Curve? curve,
Duration? duration,
int? id,
String? routeName,
bool fullscreenDialog = false,
dynamic arguments,
Binding? binding,
bool preventDuplicates = true,
bool? popGesture,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
}) async {
routeName = _cleanRouteName("/${page.runtimeType}");
final route = GetPage<T>(
name: routeName,
opaque: opaque ?? true,
page: page,
gestureWidth: gestureWidth,
showCupertinoParallax: showCupertinoParallax,
popGesture: popGesture ?? Get.defaultPopGesture,
transition: transition ?? Get.defaultTransition,
curve: curve ?? Get.defaultTransitionCurve,
fullscreenDialog: fullscreenDialog,
binding: binding,
transitionDuration: duration ?? Get.defaultTransitionDuration,
);
final args = _buildPageSettings(routeName, arguments);
return _replace(args, route);
}
@override
Future<T?>? offAll<T>(
Widget Function() page, {
bool Function(GetPage route)? predicate,
bool opaque = true,
bool? popGesture,
int? id,
String? routeName,
dynamic arguments,
Binding? binding,
bool fullscreenDialog = false,
Transition? transition,
Curve? curve,
Duration? duration,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
}) async {
routeName = _cleanRouteName("/${page.runtimeType}");
final route = GetPage<T>(
name: routeName,
opaque: opaque,
page: page,
gestureWidth: gestureWidth,
showCupertinoParallax: showCupertinoParallax,
popGesture: popGesture ?? Get.defaultPopGesture,
transition: transition ?? Get.defaultTransition,
curve: curve ?? Get.defaultTransitionCurve,
fullscreenDialog: fullscreenDialog,
binding: binding,
transitionDuration: duration ?? Get.defaultTransitionDuration,
);
final args = _buildPageSettings(routeName, arguments);
final newPredicate = predicate ?? (route) => false;
while (_activePages.length > 1 && !newPredicate(_activePages.last)) {
_popWithResult();
}
return _push(args, route);
}
@override
Future<T?>? offAllNamed<T>(
String page, {
bool Function(GetPage route)? predicate,
dynamic arguments,
int? id,
Map<String, String>? parameters,
}) async {
final args = _buildPageSettings(page, arguments);
final route = _getPage<T>(args);
if (route == null) return null;
// final newPredicate = predicate ?? (route) => false;
while (_activePages.length > 1) {
_activePages.removeLast();
removeLastHistory(null);
}
return _replace(args, route);
}
@override
Future<T?> offNamed<T>(String page, [Object? data]) async {
final arguments = _buildPageSettings(page, data);
final route = _getPage<T>(arguments);
if (route == null) return null;
_popWithResult();
return _push<T>(arguments, route);
}
@override
Future<T?> toAndOffUntil<T>(
String page,
bool Function(GetPage) predicate, [
Object? data,
]) async {
final arguments = _buildPageSettings(page, data);
final route = _getPage<T>(arguments);
if (route == null) return null;
while (_activePages.isNotEmpty && !predicate(_activePages.last)) {
_popWithResult();
}
return _push<T>(arguments, route);
}
@override
void back<T>([T? result]) {
_checkIfCanBack();
_popWithResult<T>(result);
refresh();
}
void _checkIfCanBack() {
assert(() {
if (!canBack) {
final last = _activePages.last;
final name = last.name;
throw 'The page $name cannot be popped';
}
return true;
}());
}
@override
Future<R?> backAndtoNamed<T, R>(String page,
{T? result, Object? data}) async {
final arguments = _buildPageSettings(page, data);
final route = _getPage<R>(arguments);
if (route == null) return null;
_popWithResult<T>(result);
return _push<R>(arguments, route);
}
@override
void backUntil(bool Function(GetPage) predicate) {
while (canBack && !predicate(_activePages.last)) {
_popWithResult();
}
refresh();
}
@override
void goToUnknownPage([bool clearPages = false]) {
if (clearPages) _activePages.clear();
final page =
_buildSettings(_unknownPage, _buildPageSettings(_unknownPage.name));
_activePages.add(page);
refresh();
}
@override
bool get canBack => _activePages.length > 1;
bool _onPopPage(Route route, result) {
if (!route.didPop(result)) return false;
_popWithResult(result);
refresh();
return true;
}
@override
Widget build(BuildContext context) {
if (_activePages.isEmpty) return SizedBox.shrink();
return GetNavigator(
key: navigatorKey,
restorationScopeId: restorationScopeId,
observers: navigatorObservers,
pages: List.unmodifiable(_activePages),
onPopPage: _onPopPage,
);
}
@override
Future<void> setNewRoutePath(PageSettings configuration) async {
// if (_activePages.isEmpty) return;
final page = _getPage(configuration);
if (page == null) {
goToUnknownPage();
return;
} else {
_push(configuration, page);
}
}
@override
PageSettings? get currentConfiguration {
if (_activePages.isEmpty) {
return null;
}
return _activePages.last.arguments as PageSettings;
}
}
... ...
import 'package:flutter/widgets.dart';
import '../../../../get_state_manager/src/simple/get_state.dart';
import '../../routes/get_route.dart';
import '../../routes/transitions_type.dart';
mixin IGetNavigation {
Future<T?> to<T>(
Widget Function() page, {
bool? opaque,
Transition? transition,
Curve? curve,
Duration? duration,
int? id,
String? routeName,
bool fullscreenDialog = false,
dynamic arguments,
Binding? binding,
bool preventDuplicates = true,
bool? popGesture,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
});
Future<T?> off<T>(
Widget Function() page, {
bool? opaque,
Transition? transition,
Curve? curve,
Duration? duration,
int? id,
String? routeName,
bool fullscreenDialog = false,
dynamic arguments,
Binding? binding,
bool preventDuplicates = true,
bool? popGesture,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
});
Future<T?>? offAll<T>(
Widget Function() page, {
bool Function(GetPage route)? predicate,
bool opaque = true,
bool? popGesture,
int? id,
String? routeName,
dynamic arguments,
Binding? binding,
bool fullscreenDialog = false,
Transition? transition,
Curve? curve,
Duration? duration,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
});
Future<T?> toNamed<T>(String page, [Object? data]);
Future<T?> offNamed<T>(String page, [Object? data]);
Future<T?>? offAllNamed<T>(
String newRouteName, {
bool Function(GetPage route)? predicate,
dynamic arguments,
int? id,
Map<String, String>? parameters,
});
Future<T?> toAndOffUntil<T>(
String page,
bool Function(GetPage) predicate, [
Object? data,
]);
void back<T>([T? result]);
Future<R?> backAndtoNamed<T, R>(String page, {T? result, Object? data});
void backUntil(bool Function(GetPage) predicate);
void goToUnknownPage([bool clearPages = true]);
bool get canBack;
}
... ...
export 'get_navigation_imp.dart';
export 'get_navigation_interface.dart';
export 'new_get_information_parser.dart';
export 'page_arguments.dart';
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import '../../../../get.dart';
class NewGetInformationParser extends RouteInformationParser<PageSettings> {
final String initialRoute;
NewGetInformationParser({
required this.initialRoute,
}) {
Get.log('GetInformationParser is created !');
}
@override
SynchronousFuture<PageSettings> parseRouteInformation(
RouteInformation routeInformation,
) {
var location = routeInformation.location;
if (location == '/') {
//check if there is a corresponding page
//if not, relocate to initialRoute
if (!Get.routeTree.routes.any((element) => element.name == '/')) {
location = initialRoute;
}
}
Get.log('GetInformationParser: route location: $location');
// final matchResult = Get.routeTree.matchRoute(location ?? initialRoute);
return SynchronousFuture(
PageSettings(
Uri.parse(location!),
),
);
}
@override
RouteInformation restoreRouteInformation(PageSettings config) {
return RouteInformation(
location: config.name,
state: null,
);
}
}
... ...
import 'package:flutter/widgets.dart';
extension PageArgExt on BuildContext {
PageSettings get arguments {
return ModalRoute.of(this)!.settings.arguments as PageSettings;
}
}
class PageSettings extends RouteSettings {
PageSettings(
this.uri, [
this.arguments,
]);
@override
String get name => '$uri';
@override
late final Object? arguments;
final Uri uri;
final params = <String, String>{};
String get path => uri.path;
List<String> get paths => uri.pathSegments;
Map<String, String> get query => uri.queryParameters;
Map<String, List<String>> get queries => uri.queryParametersAll;
@override
String toString() => name;
PageSettings copy({
Uri? uri,
Object? arguments,
}) {
return PageSettings(
uri ?? this.uri,
arguments ?? this.arguments,
);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is PageSettings &&
other.uri == uri &&
other.arguments == arguments;
}
@override
int get hashCode => uri.hashCode ^ arguments.hashCode;
}
... ...
void removeHash() {}
void removeLastHistory(String? url){
}
... ...
import 'web/web_url.dart' if (dart.library.io) 'io/io_url.dart';
void setUrlStrategy() {
removeHash();
}
void removeLastHistory(String? url) {
removeLastHistory(url);
}
... ...
import 'dart:html';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
void removeHash() {
setUrlStrategy(PathUrlStrategy());
}
void removeLastHistory(String? url) {
window.location.replace(null);
}
... ...
import '../../get_navigation.dart';
class RouteDecoder {
final List<GetPage> treeBranch;
GetPage? get route => treeBranch.isEmpty ? null : treeBranch.last;
class RouteDecoder<T> {
final List<GetPage<T>> treeBranch;
GetPage<T>? get route => treeBranch.isEmpty ? null : treeBranch.last;
final Map<String, String> parameters;
final Object? arguments;
const RouteDecoder(
... ... @@ -98,6 +98,19 @@ class ParseRouteTree {
}
}
void removeRoutes(List<GetPage> getPages) {
for (final route in getPages) {
removeRoute(route);
}
}
void removeRoute(GetPage route) {
routes.remove(route);
for (var page in _flattenPage(route)) {
removeRoute(page);
}
}
void addRoute(GetPage route) {
routes.add(route);
... ...
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
... ... @@ -24,6 +26,7 @@ class GetPage<T> extends Page<T> {
final Duration? transitionDuration;
final bool fullscreenDialog;
final bool preventDuplicates;
final Completer<T?>? completer;
// @override
// final LocalKey? key;
... ... @@ -67,6 +70,7 @@ class GetPage<T> extends Page<T> {
this.arguments,
this.showCupertinoParallax = true,
this.preventDuplicates = true,
this.completer,
}) : path = _nameToRegex(name),
assert(name.startsWith('/'),
'It is necessary to start route name [$name] with a slash: /$name'),
... ... @@ -102,6 +106,7 @@ class GetPage<T> extends Page<T> {
bool? participatesInRootNavigator,
Object? arguments,
bool? showCupertinoParallax,
Completer<T?>? completer,
}) {
return GetPage(
participatesInRootNavigator:
... ... @@ -129,6 +134,7 @@ class GetPage<T> extends Page<T> {
arguments: arguments ?? this.arguments,
showCupertinoParallax:
showCupertinoParallax ?? this.showCupertinoParallax,
completer: completer ?? this.completer,
);
}
... ... @@ -164,6 +170,17 @@ class GetPage<T> extends Page<T> {
return PathDecoded(RegExp('^$stringPath\$'), keys);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is GetPage<T> && other.key == key;
}
@override
int get hashCode {
return key.hashCode;
}
}
@immutable
... ...
... ... @@ -73,8 +73,11 @@ mixin StateMixin<T> on ListNotifier {
} else {
status = GetState<T>.success(newValue);
}
refresh();
}, onError: (err) {
status = GetState.error(errorMessage ?? err.toString());
refresh();
});
}
}
... ...
... ... @@ -9,6 +9,8 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_web_plugins:
sdk: flutter
dev_dependencies:
flutter_test:
... ...