init
This commit is contained in:
189
lib/app/router/app_navigator.dart
Normal file
189
lib/app/router/app_navigator.dart
Normal file
@@ -0,0 +1,189 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppNavigator {
|
||||
AppNavigator._();
|
||||
|
||||
static final navigatorKey = GlobalKey<NavigatorState>();
|
||||
static final Set<String> _pushingRoutes = <String>{};
|
||||
|
||||
static BuildContext? get context => navigatorKey.currentContext;
|
||||
|
||||
static Future<T?> push<T>(
|
||||
Widget page, {
|
||||
BuildContext? context,
|
||||
Object? arguments,
|
||||
String? name,
|
||||
bool preventDuplicate = true,
|
||||
}) async {
|
||||
final routeName = name ?? page.runtimeType.toString();
|
||||
if (preventDuplicate && RouteTracker.contains(routeName)) {
|
||||
return null;
|
||||
}
|
||||
if (_pushingRoutes.contains(routeName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
_pushingRoutes.add(routeName);
|
||||
final nav = Navigator.of(
|
||||
context ?? AppNavigator.context!,
|
||||
rootNavigator: true,
|
||||
);
|
||||
try {
|
||||
return await nav.push<T>(
|
||||
SlidePageRoute(
|
||||
builder: (_) => page,
|
||||
settings: RouteSettings(name: routeName, arguments: arguments),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_pushingRoutes.remove(routeName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static Future<T?> pushReplacement<T, TO>(
|
||||
Widget page, {
|
||||
BuildContext? context,
|
||||
Object? arguments,
|
||||
String? name,
|
||||
}) {
|
||||
return Navigator.of(
|
||||
context ?? AppNavigator.context!,
|
||||
rootNavigator: true,
|
||||
).pushReplacement<T, TO>(
|
||||
SlidePageRoute(
|
||||
builder: (_) => page,
|
||||
settings: RouteSettings(name: name, arguments: arguments),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<T?> pushAndRemoveUntil<T>(
|
||||
Widget page, {
|
||||
BuildContext? context,
|
||||
RoutePredicate? predicate,
|
||||
Object? arguments,
|
||||
String? name,
|
||||
}) {
|
||||
return Navigator.of(
|
||||
context ?? AppNavigator.context!,
|
||||
rootNavigator: true,
|
||||
).pushAndRemoveUntil<T>(
|
||||
SlidePageRoute(
|
||||
builder: (_) => page,
|
||||
settings: RouteSettings(name: name, arguments: arguments),
|
||||
),
|
||||
predicate ?? (_) => false,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<T?> pushTransparent<T>(
|
||||
Widget page, {
|
||||
BuildContext? context,
|
||||
Color barrierColor = Colors.black54,
|
||||
Duration duration = const Duration(milliseconds: 200),
|
||||
bool dismissible = true,
|
||||
}) {
|
||||
return Navigator.of(context ?? AppNavigator.context!).push<T>(
|
||||
PageRouteBuilder<T>(
|
||||
opaque: false,
|
||||
barrierColor: barrierColor,
|
||||
barrierDismissible: dismissible,
|
||||
transitionDuration: duration,
|
||||
reverseTransitionDuration: duration,
|
||||
pageBuilder: (_, __, ___) => page,
|
||||
transitionsBuilder: (_, animation, __, child) {
|
||||
return FadeTransition(opacity: animation, child: child);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static void pop<T extends Object?>({BuildContext? context, T? result}) {
|
||||
Navigator.of(
|
||||
context ?? AppNavigator.context!,
|
||||
rootNavigator: true,
|
||||
).pop<T>(result);
|
||||
}
|
||||
|
||||
static void popTimes({BuildContext? context, int count = 1}) {
|
||||
var popped = 0;
|
||||
Navigator.of(context ?? AppNavigator.context!).popUntil((route) {
|
||||
if (popped < count) {
|
||||
popped++;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SlidePageRoute<T> extends MaterialPageRoute<T> {
|
||||
SlidePageRoute({required super.builder, super.settings});
|
||||
|
||||
@override
|
||||
Widget buildTransitions(
|
||||
BuildContext context,
|
||||
Animation<double> animation,
|
||||
Animation<double> secondaryAnimation,
|
||||
Widget child,
|
||||
) {
|
||||
if (Platform.isAndroid) {
|
||||
final tween = Tween(
|
||||
begin: const Offset(1, 0),
|
||||
end: Offset.zero,
|
||||
).chain(CurveTween(curve: Curves.easeOutCubic));
|
||||
return SlideTransition(position: animation.drive(tween), child: child);
|
||||
}
|
||||
|
||||
return Theme.of(context).pageTransitionsTheme.buildTransitions<T>(
|
||||
this,
|
||||
context,
|
||||
animation,
|
||||
secondaryAnimation,
|
||||
child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RouteTracker extends NavigatorObserver {
|
||||
static final List<String?> pageStack = [];
|
||||
|
||||
bool _isPage(Route<dynamic> route) => route is PageRoute;
|
||||
|
||||
@override
|
||||
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (_isPage(route)) {
|
||||
pageStack.add(route.settings.name);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (_isPage(route) && pageStack.isNotEmpty) {
|
||||
pageStack.removeLast();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
||||
if (_isPage(route)) {
|
||||
pageStack.remove(route.settings.name);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
|
||||
if (oldRoute != null && _isPage(oldRoute) && pageStack.isNotEmpty) {
|
||||
pageStack.removeLast();
|
||||
}
|
||||
if (newRoute != null && _isPage(newRoute)) {
|
||||
pageStack.add(newRoute.settings.name);
|
||||
}
|
||||
}
|
||||
|
||||
static bool contains(String name) => pageStack.contains(name);
|
||||
}
|
||||
Reference in New Issue
Block a user