Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
fluttertpc_get
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
Jonny Borges
2022-02-26 23:23:17 +0000
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
42d65a578c99670846b06b2f049d98eaa8fe1fb3
42d65a57
1 parent
b8b33e47
add more navigation options, fix child middlewares, dispose of subroutes
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
665 additions
and
516 deletions
example_nav2/lib/app/modules/home/views/home_view.dart
example_nav2/lib/app/modules/product_details/controllers/product_details_controller.dart
example_nav2/lib/app/modules/products/bindings/products_binding.dart
example_nav2/lib/app/modules/products/views/products_view.dart
example_nav2/lib/app/modules/root/views/root_view.dart
example_nav2/lib/app/routes/app_pages.dart
example_nav2/pubspec.yaml
example_nav2/windows/flutter/generated_plugin_registrant.cc
example_nav2/windows/flutter/generated_plugin_registrant.h
lib/get_navigation/src/routes/get_navigation_interface.dart
lib/get_navigation/src/routes/get_navigator.dart
lib/get_navigation/src/routes/get_route.dart
lib/get_navigation/src/routes/get_router_delegate.dart
lib/get_navigation/src/routes/get_transition_mixin.dart
lib/get_navigation/src/routes/index.dart
lib/get_navigation/src/routes/parse_route.dart
lib/get_state_manager/src/rx_flutter/rx_notifier.dart
lib/get_state_manager/src/simple/get_state.dart
pubspec.yaml
test/navigation/routes_test.dart
example_nav2/lib/app/modules/home/views/home_view.dart
View file @
42d65a5
...
...
@@ -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),
),
...
...
example_nav2/lib/app/modules/product_details/controllers/product_details_controller.dart
View file @
42d65a5
...
...
@@ -13,6 +13,7 @@ class ProductDetailsController extends GetxController {
@override
void
onClose
()
{
Get
.
log
(
'ProductDetailsController close with id:
$productId
'
);
super
.
onClose
();
}
}
...
...
example_nav2/lib/app/modules/products/bindings/products_binding.dart
View file @
42d65a5
...
...
@@ -2,13 +2,11 @@ import 'package:get/get.dart';
import
'../controllers/products_controller.dart'
;
class
ProductsBinding
extends
Binding
{
class
ProductsBinding
extends
Binding
s
{
@override
List
<
Bind
>
dependencies
()
{
return
[
Bind
.
lazyPut
<
ProductsController
>(
()
=>
ProductsController
(),
)
];
void
dependencies
()
{
Get
.
lazyPut
<
ProductsController
>(
()
=>
ProductsController
(),
);
}
}
...
...
example_nav2/lib/app/modules/products/views/products_view.dart
View file @
42d65a5
...
...
@@ -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
(
...
...
example_nav2/lib/app/modules/root/views/root_view.dart
View file @
42d65a5
...
...
@@ -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
);
},
),
...
...
example_nav2/lib/app/routes/app_pages.dart
View file @
42d65a5
...
...
@@ -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
(
...
...
example_nav2/pubspec.yaml
View file @
42d65a5
...
...
@@ -12,6 +12,7 @@ dependencies:
path
:
../
flutter
:
sdk
:
flutter
flutter_lints
:
^1.0.4
dev_dependencies
:
flutter_test
:
...
...
example_nav2/windows/flutter/generated_plugin_registrant.cc
View file @
42d65a5
...
...
@@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#include "generated_plugin_registrant.h"
...
...
example_nav2/windows/flutter/generated_plugin_registrant.h
View file @
42d65a5
...
...
@@ -2,6 +2,8 @@
// Generated file. Do not edit.
//
// clang-format off
#ifndef GENERATED_PLUGIN_REGISTRANT_
#define GENERATED_PLUGIN_REGISTRANT_
...
...
lib/get_navigation/src/routes/get_navigation_interface.dart
View file @
42d65a5
...
...
@@ -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
,
...
...
lib/get_navigation/src/routes/get_navigator.dart
View file @
42d65a5
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:
...
...
lib/get_navigation/src/routes/get_route.dart
View file @
42d65a5
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
;
}
...
...
lib/get_navigation/src/routes/get_router_delegate.dart
View file @
42d65a5
...
...
@@ -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
;
}
}
...
...
lib/get_navigation/src/routes/get_transition_mixin.dart
View file @
42d65a5
...
...
@@ -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
=
30
0
;
// 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
(
_kMax
Droppe
dSwipePageForwardAnimationTime
,
0
,
controller
.
value
)!
_kMax
Mi
dSwipePageForwardAnimationTime
,
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
,
_kMax
Droppe
dSwipePageForwardAnimationTime
,
controller
.
value
)!
0
,
_kMax
Mi
dSwipePageForwardAnimationTime
,
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
Cupertino
BackGestureDetector when a pop ("back") drag start
// Called by
Get
BackGestureDetector 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
);
}
}
}
...
...
lib/get_navigation/src/routes/index.dart
View file @
42d65a5
...
...
@@ -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'
;
...
...
lib/get_navigation/src/routes/parse_route.dart
View file @
42d65a5
...
...
@@ -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
(
...
...
lib/get_state_manager/src/rx_flutter/rx_notifier.dart
View file @
42d65a5
...
...
@@ -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
...
...
lib/get_state_manager/src/simple/get_state.dart
View file @
42d65a5
...
...
@@ -129,7 +129,7 @@ abstract class Bind<T> extends StatelessWidget {
static
Bind
lazyPut
<
S
>(
InstanceBuilderCallback
<
S
>
builder
,
{
String
?
tag
,
bool
fenix
=
fals
e
,
bool
fenix
=
tru
e
,
})
{
Get
.
lazyPut
<
S
>(
builder
,
tag:
tag
,
fenix:
fenix
);
return
_FactoryBind
<
S
>(
...
...
pubspec.yaml
View file @
42d65a5
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
:
...
...
test/navigation/routes_test.dart
View file @
42d65a5
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),
// );
// });
}
...
...
Please
register
or
login
to post a comment