Jonny Borges

add more navigation options, fix child middlewares, dispose of subroutes

... ... @@ -5,6 +5,7 @@ import '../../../routes/app_pages.dart';
import '../controllers/home_controller.dart';
class HomeView extends GetView<HomeController> {
const HomeView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetRouterOutlet.builder(
... ... @@ -24,6 +25,7 @@ class HomeView extends GetView<HomeController> {
body: GetRouterOutlet(
initialRoute: Routes.DASHBOARD,
anchorRoute: Routes.HOME,
//delegate: Get.nestedKey(Routes.HOME),
// key: Get.nestedKey(Routes.HOME),
),
... ...
... ... @@ -13,6 +13,7 @@ class ProductDetailsController extends GetxController {
@override
void onClose() {
Get.log('ProductDetailsController close with id: $productId');
super.onClose();
}
}
... ...
... ... @@ -2,13 +2,11 @@ import 'package:get/get.dart';
import '../controllers/products_controller.dart';
class ProductsBinding extends Binding {
class ProductsBinding extends Bindings {
@override
List<Bind> dependencies() {
return [
Bind.lazyPut<ProductsController>(
() => ProductsController(),
)
];
void dependencies() {
Get.lazyPut<ProductsController>(
() => ProductsController(),
);
}
}
... ...
... ... @@ -5,11 +5,12 @@ import '../../../routes/app_pages.dart';
import '../controllers/products_controller.dart';
class ProductsView extends GetView<ProductsController> {
const ProductsView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: controller.loadDemoProductsFromSomeWhere,
onPressed: () => controller.loadDemoProductsFromSomeWhere(),
label: Text('Add'),
),
body: Column(
... ...
... ... @@ -25,6 +25,9 @@ class RootView extends GetView<RootController> {
delegate: Get.nestedKey(null),
anchorRoute: '/',
filterPages: (afterAnchor) {
// print(afterAnchor);
// print('dddddddddddddddddd');
// print(afterAnchor.take(1));
return afterAnchor.take(1);
},
),
... ...
... ... @@ -45,7 +45,7 @@ class AppPages {
GetPage(
preventDuplicates: true,
name: _Paths.HOME,
page: () => HomeView(),
page: () => const HomeView(),
bindings: [
HomeBinding(),
],
... ... @@ -71,9 +71,10 @@ class AppPages {
),
GetPage(
name: _Paths.PRODUCTS,
page: () => ProductsView(),
page: () => const ProductsView(),
title: 'Products',
transition: Transition.zoom,
participatesInRootNavigator: false,
bindings: [ProductsBinding()],
children: [
GetPage(
... ...
... ... @@ -12,6 +12,7 @@ dependencies:
path: ../
flutter:
sdk: flutter
flutter_lints: ^1.0.4
dev_dependencies:
flutter_test:
... ...
... ... @@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
... ...
... ... @@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
... ...
... ... @@ -4,6 +4,49 @@ import '../../../get_instance/src/bindings_interface.dart';
import '../routes/get_route.dart';
import '../routes/transitions_type.dart';
/// Enables the user to customize the intended pop behavior
///
/// Goes to either the previous _activePages entry or the previous page entry
///
/// e.g. if the user navigates to these pages
/// 1) /home
/// 2) /home/products/1234
///
/// when popping on [History] mode, it will emulate a browser back button.
///
/// so the new _activePages stack will be:
/// 1) /home
///
/// when popping on [Page] mode, it will only remove the last part of the route
/// so the new _activePages stack will be:
/// 1) /home
/// 2) /home/products
///
/// another pop will change the _activePages stack to:
/// 1) /home
enum PopMode {
History,
Page,
}
/// Enables the user to customize the behavior when pushing multiple routes that
/// shouldn't be duplicates
enum PreventDuplicateHandlingMode {
/// Removes the _activePages entries until it reaches the old route
PopUntilOriginalRoute,
/// Simply don't push the new route
DoNothing,
/// Recommended - Moves the old route entry to the front
///
/// With this mode, you guarantee there will be only one
/// route entry for each location
ReorderRoutes,
Recreate,
}
mixin IGetNavigation {
Future<T?> to<T>(
Widget Function() page, {
... ... @@ -22,6 +65,11 @@ mixin IGetNavigation {
double Function(BuildContext context)? gestureWidth,
});
Future<void> popModeUntil(
String fullRoute, {
PopMode popMode = PopMode.History,
});
Future<T?> off<T>(
Widget Function() page, {
bool? opaque,
... ...
import 'package:flutter/widgets.dart';
import '../routes/default_route.dart';
import '../routes/get_route.dart';
import '../../../get.dart';
class GetNavigator extends Navigator {
GetNavigator.onGenerateRoute({
... ... @@ -72,7 +71,8 @@ class GetNavigator extends Navigator {
restorationScopeId: restorationScopeId,
pages: pages,
observers: [
// GetObserver(),
// GetObserver(null, Get.routing),
HeroController(),
...?observers,
],
transitionDelegate:
... ...
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../get_instance/src/bindings_interface.dart';
... ... @@ -186,6 +187,10 @@ class GetPage<T> extends Page<T> {
}
@override
String toString() =>
'${objectRuntimeType(this, 'Page')}("$name", $key, $arguments)';
@override
int get hashCode {
return key.hashCode;
}
... ...
... ... @@ -7,50 +7,6 @@ import '../../../get_instance/src/bindings_interface.dart';
import '../../../get_state_manager/src/simple/list_notifier.dart';
import '../../../get_utils/src/platform/platform.dart';
import '../../../route_manager.dart';
import 'parse_route.dart';
/// Enables the user to customize the intended pop behavior
///
/// Goes to either the previous _activePages entry or the previous page entry
///
/// e.g. if the user navigates to these pages
/// 1) /home
/// 2) /home/products/1234
///
/// when popping on [History] mode, it will emulate a browser back button.
///
/// so the new _activePages stack will be:
/// 1) /home
///
/// when popping on [Page] mode, it will only remove the last part of the route
/// so the new _activePages stack will be:
/// 1) /home
/// 2) /home/products
///
/// another pop will change the _activePages stack to:
/// 1) /home
enum PopMode {
History,
Page,
}
/// Enables the user to customize the behavior when pushing multiple routes that
/// shouldn't be duplicates
enum PreventDuplicateHandlingMode {
/// Removes the _activePages entries until it reaches the old route
PopUntilOriginalRoute,
/// Simply don't push the new route
DoNothing,
/// Recommended - Moves the old route entry to the front
///
/// With this mode, you guarantee there will be only one
/// route entry for each location
ReorderRoutes,
Recreate,
}
class GetDelegate extends RouterDelegate<RouteDecoder>
with
... ... @@ -69,6 +25,8 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
final Iterable<GetPage> Function(RouteDecoder currentNavStack)?
pickPagesForRootNavigator;
List<RouteDecoder> get activePages => _activePages;
// GlobalKey<NavigatorState> get navigatorKey => Get.key;
@override
... ... @@ -124,6 +82,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
Future<T?> _unsafeHistoryRemove<T>(RouteDecoder config, T result) async {
var index = _activePages.indexOf(config);
if (index >= 0) return _unsafeHistoryRemoveAt(index, result);
return null;
}
Future<T?> _unsafeHistoryRemoveAt<T>(int index, T result) async {
... ... @@ -295,13 +254,17 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
final currentHistory = currentConfiguration;
final pages = currentHistory == null
? <GetPage>[]
: pickPagesForRootNavigator?.call(currentHistory) ??
getVisualPages(currentHistory);
if (pages.length == 0) return SizedBox.shrink();
: pickPagesForRootNavigator?.call(currentHistory).toList() ??
getVisualPages(currentHistory).toList();
if (pages.length == 0) {
return ColoredBox(
color: Theme.of(context).scaffoldBackgroundColor,
);
}
return GetNavigator(
key: navigatorKey,
onPopPage: _onPopVisualRoute,
pages: pages.toList(),
pages: pages,
observers: navigatorObservers,
transitionDelegate:
transitionDelegate ?? const DefaultTransitionDelegate<dynamic>(),
... ... @@ -339,30 +302,33 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
} else {
goToUnknownPage();
}
return null;
}
@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,
List<BindingsInterface> bindings = const [],
bool preventDuplicates = true,
bool? popGesture,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
bool rebuildStack = true,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes}) async {
Future<T?> to<T>(
Widget Function() page, {
bool? opaque,
Transition? transition,
Curve? curve,
Duration? duration,
int? id,
String? routeName,
bool fullscreenDialog = false,
dynamic arguments,
List<BindingsInterface> bindings = const [],
bool preventDuplicates = true,
bool? popGesture,
bool showCupertinoParallax = true,
double Function(BuildContext context)? gestureWidth,
bool rebuildStack = true,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes,
}) async {
routeName = _cleanRouteName("/${page.runtimeType}");
if (preventDuplicateHandlingMode == PreventDuplicateHandlingMode.Recreate) {
routeName = routeName + page.hashCode.toString();
}
// if (preventDuplicateHandlingMode == PreventDuplicateHandlingMode.Recreate) {
// routeName = routeName + page.hashCode.toString();
// }
final getPage = GetPage<T>(
name: routeName,
... ... @@ -385,7 +351,6 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
final result = await _push<T>(
route!,
rebuildStack: rebuildStack,
preventDuplicateHandlingMode: preventDuplicateHandlingMode,
);
Get.removePage(getPage);
return result;
... ... @@ -708,14 +673,15 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
return decoder;
}
Future<T?> _push<T>(RouteDecoder decoder,
{bool rebuildStack = true,
PreventDuplicateHandlingMode preventDuplicateHandlingMode =
PreventDuplicateHandlingMode.ReorderRoutes}) async {
Future<T?> _push<T>(RouteDecoder decoder, {bool rebuildStack = true}) async {
var mid = await runMiddleware(decoder);
final res = mid ?? decoder;
// if (res == null) res = decoder;
final preventDuplicateHandlingMode =
res.route?.preventDuplicateHandlingMode ??
PreventDuplicateHandlingMode.ReorderRoutes;
final onStackPage = _activePages
.firstWhereOrNull((element) => element.route?.key == res.route?.key);
... ... @@ -815,7 +781,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
}
}
refresh();
//return !route.navigator!.userGestureInProgress;
return true;
}
}
... ...
... ... @@ -9,35 +9,160 @@ import 'package:flutter/material.dart';
import '../../../get.dart';
const double _kBackGestureWidth = 20.0;
const int _kMaxDroppedSwipePageForwardAnimationTime =
800; // Screen widths per second.
// An eyeballed value for the maximum time it takes
//for a page to animate forward
// if the user releases a page mid swipe.
const int _kMaxPageBackAnimationTime = 300; // Milliseconds.
const double _kMinFlingVelocity = 1; // Screen widths per second.
// An eyeballed value for the maximum time it takes for a page to animate
// forward if the user releases a page mid swipe.
const int _kMaxMidSwipePageForwardAnimationTime = 800; // Milliseconds.
// The maximum time for a page to get reset to it's original position if the
// user releases a page mid swipe.
const double _kMinFlingVelocity = 1.0; // Milliseconds.
const int _kMaxPageBackAnimationTime = 300; // Milliseconds.
class CupertinoBackGestureController<T> {
final AnimationController controller;
class GetBackGestureDetector<T> extends StatefulWidget {
const GetBackGestureDetector({
Key? key,
required this.limitedSwipe,
required this.gestureWidth,
required this.initialOffset,
required this.popGestureEnable,
required this.onStartPopGesture,
required this.child,
}) : super(key: key);
final NavigatorState navigator;
final bool limitedSwipe;
final double gestureWidth;
final double initialOffset;
/// Creates a controller for an iOS-style back gesture.
///
/// The [navigator] and [controller] arguments must not be null.
CupertinoBackGestureController({
final Widget child;
final ValueGetter<bool> popGestureEnable;
final ValueGetter<GetBackGestureController<T>> onStartPopGesture;
@override
GetBackGestureDetectorState<T> createState() =>
GetBackGestureDetectorState<T>();
}
class GetBackGestureDetectorState<T> extends State<GetBackGestureDetector<T>> {
GetBackGestureController<T>? _backGestureController;
void _handleDragStart(DragStartDetails details) {
assert(mounted);
assert(_backGestureController == null);
_backGestureController = widget.onStartPopGesture();
}
void _handleDragUpdate(DragUpdateDetails details) {
assert(mounted);
assert(_backGestureController != null);
_backGestureController!.dragUpdate(
_convertToLogical(details.primaryDelta! / context.size!.width),
);
}
void _handleDragEnd(DragEndDetails details) {
assert(mounted);
assert(_backGestureController != null);
_backGestureController!.dragEnd(_convertToLogical(
details.velocity.pixelsPerSecond.dx / context.size!.width,
));
_backGestureController = null;
}
void _handleDragCancel() {
assert(mounted);
// This can be called even if start is not called, paired with the "down"
// event that we don't consider here.
_backGestureController?.dragEnd(0);
_backGestureController = null;
}
double _convertToLogical(double value) {
switch (Directionality.of(context)) {
case TextDirection.rtl:
return -value;
case TextDirection.ltr:
return value;
}
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasDirectionality(context));
final gestureDetector = RawGestureDetector(
behavior: HitTestBehavior.translucent,
gestures: {
_DirectionalityDragGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
_DirectionalityDragGestureRecognizer>(
() {
final directionality = Directionality.of(context);
return _DirectionalityDragGestureRecognizer(
debugOwner: this,
isRTL: directionality == TextDirection.rtl,
isLTR: directionality == TextDirection.ltr,
hasbackGestureController: () => _backGestureController != null,
popGestureEnable: widget.popGestureEnable,
);
},
(directionalityDragGesture) => directionalityDragGesture
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd
..onCancel = _handleDragCancel,
)
},
);
return Stack(
fit: StackFit.passthrough,
children: [
widget.child,
if (widget.limitedSwipe)
PositionedDirectional(
start: widget.initialOffset,
width: _dragAreaWidth(context),
top: 0,
bottom: 0,
child: gestureDetector,
)
else
Positioned.fill(child: gestureDetector),
],
);
}
double _dragAreaWidth(BuildContext context) {
// For devices with notches, the drag area needs to be larger on the side
// that has the notch.
final dragAreaWidth = Directionality.of(context) == TextDirection.ltr
? context.mediaQuery.padding.left
: context.mediaQuery.padding.right;
return max(dragAreaWidth, widget.gestureWidth);
}
}
class GetBackGestureController<T> {
GetBackGestureController({
required this.navigator,
required this.controller,
}) {
navigator.didStartUserGesture();
}
/// The drag gesture has ended with a horizontal motion of
/// [fractionalVelocity] as a fraction of screen width per second.
final AnimationController controller;
final NavigatorState navigator;
/// The drag gesture has changed by [delta]. The total range of the
/// drag should be 0.0 to 1.0.
void dragUpdate(double delta) {
controller.value -= delta;
}
/// The drag gesture has ended with a horizontal motion of [velocity] as a
/// fraction of screen width per second.
void dragEnd(double velocity) {
// Fling in the appropriate direction.
// AnimationController.fling is guaranteed to
... ... @@ -63,7 +188,7 @@ class CupertinoBackGestureController<T> {
// to determine it.
final droppedPageForwardAnimationTime = min(
lerpDouble(
_kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)!
_kMaxMidSwipePageForwardAnimationTime, 0, controller.value)!
.floor(),
_kMaxPageBackAnimationTime,
);
... ... @@ -72,14 +197,14 @@ class CupertinoBackGestureController<T> {
curve: animationCurve);
} else {
// This route is destined to pop at this point. Reuse navigator's pop.
navigator.pop();
Get.back();
// The popping may have finished inline if already at the
// target destination.
if (controller.isAnimating) {
// Otherwise, use a custom popping animation duration and curve.
final droppedPageBackAnimationTime = lerpDouble(
0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)!
0, _kMaxMidSwipePageForwardAnimationTime, controller.value)!
.floor();
controller.animateBack(0.0,
duration: Duration(milliseconds: droppedPageBackAnimationTime),
... ... @@ -101,126 +226,6 @@ class CupertinoBackGestureController<T> {
navigator.didStopUserGesture();
}
}
/// The drag gesture has changed by [fractionalDelta]. The total range of the
/// drag should be 0.0 to 1.0.
void dragUpdate(double delta) {
controller.value -= delta;
}
}
class CupertinoBackGestureDetector<T> extends StatefulWidget {
final Widget child;
final double gestureWidth;
final ValueGetter<bool> enabledCallback;
final ValueGetter<CupertinoBackGestureController<T>> onStartPopGesture;
const CupertinoBackGestureDetector({
Key? key,
required this.enabledCallback,
required this.onStartPopGesture,
required this.child,
required this.gestureWidth,
}) : super(key: key);
@override
CupertinoBackGestureDetectorState<T> createState() =>
CupertinoBackGestureDetectorState<T>();
}
class CupertinoBackGestureDetectorState<T>
extends State<CupertinoBackGestureDetector<T>> {
CupertinoBackGestureController<T>? _backGestureController;
late HorizontalDragGestureRecognizer _recognizer;
@override
Widget build(BuildContext context) {
assert(debugCheckHasDirectionality(context));
// For devices with notches, the drag area needs to be larger on the side
// that has the notch.
var dragAreaWidth = Directionality.of(context) == TextDirection.ltr
? MediaQuery.of(context).padding.left
: MediaQuery.of(context).padding.right;
dragAreaWidth = max(dragAreaWidth, widget.gestureWidth);
return Stack(
fit: StackFit.passthrough,
children: <Widget>[
widget.child,
PositionedDirectional(
start: 0.0,
width: dragAreaWidth,
top: 0.0,
bottom: 0.0,
child: Listener(
onPointerDown: _handlePointerDown,
behavior: HitTestBehavior.translucent,
),
),
],
);
}
@override
void dispose() {
_recognizer.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
_recognizer = HorizontalDragGestureRecognizer(debugOwner: this)
..onStart = _handleDragStart
..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd
..onCancel = _handleDragCancel;
}
double _convertToLogical(double value) {
switch (Directionality.of(context)) {
case TextDirection.rtl:
return -value;
case TextDirection.ltr:
return value;
}
}
void _handleDragCancel() {
assert(mounted);
// This can be called even if start is not called, paired with
// the "down" event
// that we don't consider here.
_backGestureController?.dragEnd(0.0);
_backGestureController = null;
}
void _handleDragEnd(DragEndDetails details) {
assert(mounted);
assert(_backGestureController != null);
_backGestureController!.dragEnd(_convertToLogical(
details.velocity.pixelsPerSecond.dx / context.size!.width));
_backGestureController = null;
}
void _handleDragStart(DragStartDetails details) {
assert(mounted);
assert(_backGestureController == null);
_backGestureController = widget.onStartPopGesture();
}
void _handleDragUpdate(DragUpdateDetails details) {
assert(mounted);
assert(_backGestureController != null);
_backGestureController!.dragUpdate(
_convertToLogical(details.primaryDelta! / context.size!.width));
}
void _handlePointerDown(PointerDownEvent event) {
if (widget.enabledCallback()) _recognizer.addPointer(event);
}
}
mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {
... ... @@ -234,17 +239,6 @@ mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {
double Function(BuildContext context)? get gestureWidth;
/// Whether a pop gesture can be started by the user.
///
/// Returns true if the user can edge-swipe to a previous route.
///
/// Returns false once [isPopGestureInProgress] is true, but
/// [isPopGestureInProgress] can only become true if [popGestureEnabled] was
/// true first.
///
/// This should only be used between frames, not during build.
bool get popGestureEnabled => _isPopGestureEnabled(this);
/// True if an iOS-style back swipe pop gesture is currently
/// underway for this route.
///
... ... @@ -254,7 +248,7 @@ mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {
/// is currently underway for specific route.
/// * [popGestureEnabled], which returns true if a user-triggered pop gesture
/// would be allowed.
bool get popGestureInProgress => isPopGestureInProgress(this);
//bool get popGestureInProgress => isPopGestureInProgress(this);
/// The title string of the previous [CupertinoPageRoute].
///
... ... @@ -341,6 +335,9 @@ Cannot read the previousTitle for a route that has not yet been installed''',
super.didChangePrevious(previousRoute);
}
static bool canSwipe(GetPageRoute route) =>
route.popGesture ?? Get.defaultPopGesture;
/// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full
/// screen dialog, otherwise a [CupertinoPageTransition] is returned.
///
... ... @@ -360,15 +357,18 @@ Cannot read the previousTitle for a route that has not yet been installed''',
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
Widget child, {
bool limitedSwipe = false,
double initialOffset = 0,
}) {
// Check if the route has an animation that's currently participating
// in a back swipe gesture.
//
// In the middle of a back gesture drag, let the transition be linear to
// match finger motions.
final route = rawRoute as GetPageRoute<T>;
final linearTransition = isPopGestureInProgress(route);
final linearTransition =
CupertinoRouteTransitionMixin.isPopGestureInProgress(route);
final finalCurve = route.curve ?? Get.defaultTransitionCurve;
final hasCurve = route.curve != null;
if (route.fullscreenDialog && route.transition == null) {
... ... @@ -388,14 +388,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child,
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
),
);
}
... ... @@ -411,14 +416,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.downToUp:
return SlideDownTransition().buildTransitions(
... ... @@ -427,14 +437,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.upToDown:
return SlideTopTransition().buildTransitions(
... ... @@ -443,24 +458,34 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.noTransition:
return route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child;
return GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
);
case Transition.rightToLeft:
return SlideRightTransition().buildTransitions(
... ... @@ -469,14 +494,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.zoom:
return ZoomInTransition().buildTransitions(
... ... @@ -485,14 +515,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.fadeIn:
return FadeInTransition().buildTransitions(
... ... @@ -501,14 +536,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.rightToLeftWithFade:
return RightToLeftFadeTransition().buildTransitions(
... ... @@ -517,14 +557,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.leftToRightWithFade:
return LeftToRightFadeTransition().buildTransitions(
... ... @@ -533,28 +578,38 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.cupertino:
return CupertinoPageTransition(
primaryRouteAnimation: animation,
secondaryRouteAnimation: secondaryAnimation,
linearTransition: linearTransition,
child: CupertinoBackGestureDetector<T>(
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child,
),
);
primaryRouteAnimation: animation,
secondaryRouteAnimation: secondaryAnimation,
linearTransition: linearTransition,
child: GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.size:
return SizeTransitions().buildTransitions(
... ... @@ -563,14 +618,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.fade:
return FadeUpwardsPageTransitionsBuilder().buildTransitions(
... ... @@ -578,14 +638,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
context,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.topLevel:
return ZoomPageTransitionsBuilder().buildTransitions(
... ... @@ -593,14 +658,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
context,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.native:
return PageTransitionsTheme().buildTransitions(
... ... @@ -608,14 +678,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
context,
iosAnimation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
case Transition.circularReveal:
return CircularRevealTransition().buildTransitions(
... ... @@ -624,14 +699,19 @@ Cannot read the previousTitle for a route that has not yet been installed''',
route.alignment,
animation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
default:
if (Get.customTransition != null) {
... ... @@ -644,19 +724,24 @@ Cannot read the previousTitle for a route that has not yet been installed''',
context,
iosAnimation,
secondaryAnimation,
route.popGesture ?? Get.defaultPopGesture
? CupertinoBackGestureDetector<T>(
gestureWidth: route.gestureWidth?.call(context) ??
_kBackGestureWidth,
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
GetBackGestureDetector<T>(
popGestureEnable: () =>
_isPopGestureEnabled(route, canSwipe(route)),
onStartPopGesture: () {
assert(_isPopGestureEnabled(route, canSwipe(route)));
return _startPopGesture(route);
},
limitedSwipe: limitedSwipe,
gestureWidth:
route.gestureWidth?.call(context) ?? _kBackGestureWidth,
initialOffset: initialOffset,
child: child,
));
}
}
}
// Called by CupertinoBackGestureDetector when a pop ("back") drag start
// Called by GetBackGestureDetector when a pop ("back") drag start
// gesture is detected. The returned controller handles all of the subsequent
// drag events.
/// True if an iOS-style back swipe pop gesture is currently
... ... @@ -668,17 +753,17 @@ Cannot read the previousTitle for a route that has not yet been installed''',
///
/// * [popGestureEnabled], which returns true if a user-triggered pop gesture
/// would be allowed.
static bool isPopGestureInProgress(PageRoute<dynamic> route) {
return route.navigator!.userGestureInProgress;
}
// static bool isPopGestureInProgress(PageRoute<dynamic> route) {
// return route.navigator!.userGestureInProgress;
// }
static bool _isPopGestureEnabled<T>(PageRoute<T> route) {
static bool _isPopGestureEnabled<T>(PageRoute<T> route, bool canSwipe) {
// If there's nothing to go back to, then obviously we don't support
// the back gesture.
if (route.isFirst) return false;
// If the route wouldn't actually pop if we popped it, then the gesture
// would be really confusing (or would skip internal routes),
//so disallow it.
// so disallow it.
if (route.willHandlePopInternally) return false;
// If attempts to dismiss this route might be vetoed such as in a page
// with forms, then do not allow the user to dismiss the route with a swipe.
... ... @@ -694,19 +779,50 @@ Cannot read the previousTitle for a route that has not yet been installed''',
return false;
}
// If we're in a gesture already, we cannot start another.
if (isPopGestureInProgress(route)) return false;
if (CupertinoRouteTransitionMixin.isPopGestureInProgress(route)) {
return false;
}
// Don't perfome swipe if canSwipe be false
if (!canSwipe) return false;
// Looks like a back gesture would be welcome!
return true;
}
static CupertinoBackGestureController<T> _startPopGesture<T>(
PageRoute<T> route) {
assert(_isPopGestureEnabled(route));
return CupertinoBackGestureController<T>(
static GetBackGestureController<T> _startPopGesture<T>(
PageRoute<T> route,
) {
return GetBackGestureController<T>(
navigator: route.navigator!,
controller: route.controller!, // protected access
);
}
}
class _DirectionalityDragGestureRecognizer
extends HorizontalDragGestureRecognizer {
final ValueGetter<bool> popGestureEnable;
final ValueGetter<bool> hasbackGestureController;
final bool isRTL;
final bool isLTR;
_DirectionalityDragGestureRecognizer({
required this.isRTL,
required this.isLTR,
required this.popGestureEnable,
required this.hasbackGestureController,
Object? debugOwner,
}) : super(debugOwner: debugOwner);
@override
void handleEvent(PointerEvent event) {
final dx = event.delta.dx;
if (hasbackGestureController() ||
popGestureEnable() && (isRTL && dx < 0 || isLTR && dx > 0 || dx == 0)) {
super.handleEvent(event);
} else {
stopTrackingPointer(event.pointer);
}
}
}
... ...
... ... @@ -11,7 +11,7 @@ export 'get_transition_mixin.dart';
export 'modules.dart';
export 'observers/route_observer.dart';
export 'page_settings.dart';
export 'parse_route.dart' hide FirstWhereOrNullExt;
export 'parse_route.dart';
export 'route_middleware.dart';
export 'route_report.dart';
export 'router_outlet.dart';
... ...
... ... @@ -103,7 +103,9 @@ class ParseRouteTree {
final treeBranch = cumulativePaths
.map((e) => MapEntry(e, _findRoute(e)))
.where((element) => element.value != null)
.map((e) => MapEntry(e.key, e.value!))
///Prevent page be disposed
.map((e) => MapEntry(e.key, e.value!.copy(key: ValueKey(e.key))))
.toList();
final params = Map<String, String>.from(uri.queryParameters);
... ... @@ -210,11 +212,13 @@ class ParseRouteTree {
/// Change the Path for a [GetPage]
GetPage _addChild(
GetPage origin, String parentPath, List<GetMiddleware> middlewares) =>
origin.copy(
middlewares: middlewares,
name: (parentPath + origin.name).replaceAll(r'//', '/'),
);
GetPage origin, String parentPath, List<GetMiddleware> middlewares) {
return origin.copy(
middlewares: middlewares,
name: (parentPath + origin.name).replaceAll(r'//', '/'),
// key:
);
}
GetPage? _findRoute(String name) {
final value = routes.firstWhereOrNull(
... ...
... ... @@ -25,13 +25,13 @@ extension _Empty on Object {
}
mixin StateMixin<T> on ListNotifier {
late T _value;
T? _value;
GetStatus<T>? _status;
void _fillInitialStatus() {
_status = (value == null || value!._isEmpty())
_status = (_value == null || _value!._isEmpty())
? GetStatus<T>.loading()
: GetStatus<T>.success(_value);
: GetStatus<T>.success(_value!);
}
GetStatus<T> get status {
... ... @@ -54,7 +54,7 @@ mixin StateMixin<T> on ListNotifier {
@protected
T get value {
reportRead();
return _value;
return _value as T;
}
@protected
... ... @@ -65,19 +65,22 @@ mixin StateMixin<T> on ListNotifier {
}
@protected
void change(T newState, {GetStatus<T>? status}) {
var _canUpdate = false;
if (status != null) {
_status = status;
_canUpdate = true;
}
if (newState != _value) {
_value = newState;
_canUpdate = true;
}
if (_canUpdate) {
refresh();
void change(GetStatus<T> status) {
if (status != this.status) {
this.status = status;
}
// var _canUpdate = false;
// if (status != null) {
// _status = status;
// _canUpdate = true;
// }
// if (newState != _value) {
// _value = newState;
// _canUpdate = true;
// }
// if (_canUpdate) {
// refresh();
// }
}
void futurize(Future<T> Function() body(),
... ... @@ -184,7 +187,7 @@ class Value<T> extends ListNotifier
@override
T get value {
reportRead();
return _value;
return _value as T;
}
@override
... ...
... ... @@ -129,7 +129,7 @@ abstract class Bind<T> extends StatelessWidget {
static Bind lazyPut<S>(
InstanceBuilderCallback<S> builder, {
String? tag,
bool fenix = false,
bool fenix = true,
}) {
Get.lazyPut<S>(builder, tag: tag, fenix: fenix);
return _FactoryBind<S>(
... ...
name: get
description: Open screens/snackbars/dialogs without context, manage states and inject dependencies easily with GetX.
version: 5.0.0-beta.18
version: 5.0.0-beta.30
homepage: https://github.com/jonataslaw/getx
environment:
... ...
import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get/get.dart';
void main() {
testWidgets('Back swipe dismiss interrupted by route push', (tester) async {
// final scaffoldKey = GlobalKey();
// testWidgets('Back swipe dismiss interrupted by route push', (tester) async {
// // final scaffoldKey = GlobalKey();
await tester.pumpWidget(
GetCupertinoApp(
popGesture: true,
home: CupertinoPageScaffold(
// key: scaffoldKey,
child: Center(
child: CupertinoButton(
onPressed: () {
Get.to(
() => CupertinoPageScaffold(
child: Center(child: Text('route')),
),
preventDuplicateHandlingMode:
PreventDuplicateHandlingMode.Recreate);
},
child: const Text('push'),
),
),
),
),
);
// await tester.pumpWidget(
// GetCupertinoApp(
// popGesture: true,
// home: CupertinoPageScaffold(
// // key: scaffoldKey,
// child: Center(
// child: CupertinoButton(
// onPressed: () {
// Get.to(
// () => CupertinoPageScaffold(
// child: Center(child: Text('route')),
// ),
// preventDuplicateHandlingMode:
// PreventDuplicateHandlingMode.Recreate);
// },
// child: const Text('push'),
// ),
// ),
// ),
// ),
// );
await tester.pumpAndSettle();
// await tester.pumpAndSettle();
// Check the basic iOS back-swipe dismiss transition. Dragging the pushed
// route halfway across the screen will trigger the iOS dismiss animation
// // Check the basic iOS back-swipe dismiss transition. Dragging the pushed
// // route halfway across the screen will trigger the iOS dismiss animation
await tester.tap(find.text('push'));
await tester.pumpAndSettle();
expect(find.text('route'), findsOneWidget);
expect(find.text('push'), findsNothing);
// await tester.tap(find.text('push'));
// await tester.pumpAndSettle();
// expect(find.text('route'), findsOneWidget);
// expect(find.text('push'), findsNothing);
var gesture = await tester.startGesture(const Offset(5, 300));
await gesture.moveBy(const Offset(400, 0));
await gesture.up();
await tester.pump();
expect(
// The 'route' route has been dragged to the right, halfway across
// the screen
tester.getTopLeft(find.ancestor(
of: find.text('route'),
matching: find.byType(CupertinoPageScaffold))),
const Offset(400, 0),
);
expect(
// The 'push' route is sliding in from the left.
tester
.getTopLeft(find.ancestor(
of: find.text('push'),
matching: find.byType(CupertinoPageScaffold)))
.dx,
moreOrLessEquals(-(400 / 3), epsilon: 1),
);
await tester.pumpAndSettle();
expect(find.text('push'), findsOneWidget);
expect(
tester.getTopLeft(find.ancestor(
of: find.text('push'), matching: find.byType(CupertinoPageScaffold))),
Offset.zero,
);
expect(find.text('route'), findsNothing);
// var gesture = await tester.startGesture(const Offset(5, 300));
// await gesture.moveBy(const Offset(400, 0));
// await gesture.up();
// await tester.pump();
// expect(
// // The 'route' route has been dragged to the right, halfway across
// // the screen
// tester.getTopLeft(find.ancestor(
// of: find.text('route'),
// matching: find.byType(CupertinoPageScaffold))),
// const Offset(400, 0),
// );
// expect(
// // The 'push' route is sliding in from the left.
// tester
// .getTopLeft(find.ancestor(
// of: find.text('push'),
// matching: find.byType(CupertinoPageScaffold)))
// .dx,
// moreOrLessEquals(-(400 / 3), epsilon: 1),
// );
// await tester.pumpAndSettle();
// expect(find.text('push'), findsOneWidget);
// expect(
// tester.getTopLeft(find.ancestor(
// of: find.text('push'), matching: find.byType(CupertinoPageScaffold))),
// Offset.zero,
// );
// expect(find.text('route'), findsNothing);
// Run the dismiss animation 60%, which exposes the route "push" button,
// and then press the button.
// // Run the dismiss animation 60%, which exposes the route "push" button,
// // and then press the button.
await tester.tap(find.text('push'));
await tester.pumpAndSettle();
expect(find.text('route'), findsOneWidget);
expect(find.text('push'), findsNothing);
// await tester.tap(find.text('push'));
// await tester.pumpAndSettle();
// expect(find.text('route'), findsOneWidget);
// expect(find.text('push'), findsNothing);
gesture = await tester.startGesture(const Offset(5, 300));
await gesture.moveBy(const Offset(400, 0)); // Drag halfway.
await gesture.up();
// Trigger the snapping animation.
// Since the back swipe drag was brought to >=50% of the screen, it will
// self snap to finish the pop transition as the gesture is lifted.
//
// This drag drop animation is 400ms when dropped exactly halfway
// (800 / [pixel distance remaining], see
// _CupertinoBackGestureController.dragEnd). It follows a curve that is very
// steep initially.
await tester.pump();
expect(
tester.getTopLeft(find.ancestor(
of: find.text('route'),
matching: find.byType(CupertinoPageScaffold))),
const Offset(400, 0),
);
// Let the dismissing snapping animation go 60%.
await tester.pump(const Duration(milliseconds: 240));
expect(
tester
.getTopLeft(find.ancestor(
of: find.text('route'),
matching: find.byType(CupertinoPageScaffold)))
.dx,
moreOrLessEquals(798, epsilon: 1),
);
});
// gesture = await tester.startGesture(const Offset(5, 300));
// await gesture.moveBy(const Offset(400, 0)); // Drag halfway.
// await gesture.up();
// // Trigger the snapping animation.
// // Since the back swipe drag was brought to >=50% of the screen, it will
// // self snap to finish the pop transition as the gesture is lifted.
// //
// // This drag drop animation is 400ms when dropped exactly halfway
// // (800 / [pixel distance remaining], see
// // _CupertinoBackGestureController.dragEnd). It follows a curve that is very
// // steep initially.
// await tester.pump();
// expect(
// tester.getTopLeft(find.ancestor(
// of: find.text('route'),
// matching: find.byType(CupertinoPageScaffold))),
// const Offset(400, 0),
// );
// // Let the dismissing snapping animation go 60%.
// await tester.pump(const Duration(milliseconds: 240));
// expect(
// tester
// .getTopLeft(find.ancestor(
// of: find.text('route'),
// matching: find.byType(CupertinoPageScaffold)))
// .dx,
// moreOrLessEquals(798, epsilon: 1),
// );
// });
}
... ...