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
Ahmed Fwela
2021-06-03 07:18:12 +0200
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
7a911cf4e116ba1189fcbba37e0b462e29eec777
7a911cf4
1 parent
069ddc29
Complete rework of the navigation system (still backward compatible)
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
552 additions
and
201 deletions
example_nav2/lib/app/modules/home/views/home_view.dart
example_nav2/lib/app/modules/root/bindings/root_binding.dart
example_nav2/lib/app/modules/root/controllers/root_controller.dart
example_nav2/lib/app/modules/root/views/drawer.dart
example_nav2/lib/app/modules/root/views/root_view.dart
example_nav2/lib/app/modules/settings/views/settings_view.dart
example_nav2/lib/app/routes/app_pages.dart
example_nav2/lib/main.dart
lib/get_instance/src/extension_instance.dart
lib/get_navigation/get_navigation.dart
lib/get_navigation/src/nav2/get_information_parser.dart
lib/get_navigation/src/nav2/get_nav_config.dart
lib/get_navigation/src/nav2/get_router_delegate.dart
lib/get_navigation/src/nav2/router_outlet.dart
lib/get_navigation/src/root/parse_route.dart
lib/get_navigation/src/routes/get_route.dart
example_nav2/lib/app/modules/home/views/home_view.dart
View file @
7a911cf
import
'package:example_nav2/app/modules/home/views/dashboard_view.dart'
;
import
'package:example_nav2/app/routes/app_pages.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get_navigation/src/nav2/get_router_delegate.dart'
;
import
'package:get/get_navigation/src/nav2/router_outlet.dart'
;
import
'../../../routes/app_pages.dart'
;
import
'../controllers/home_controller.dart'
;
import
'dashboard_view.dart'
;
class
HomeView
extends
GetView
<
HomeController
>
{
@override
...
...
@@ -14,26 +11,21 @@ class HomeView extends GetView<HomeController> {
return
GetRouterOutlet
.
builder
(
builder:
(
context
,
delegate
,
currentRoute
)
{
//This router outlet handles the appbar and the bottom navigation bar
final
title
=
currentRoute
?.
title
;
final
currentName
=
currentRoute
?.
name
;
final
currentLocation
=
currentRoute
?.
location
;
var
currentIndex
=
0
;
if
(
currentName
?.
startsWith
(
Routes
.
PRODUCTS
)
==
true
)
currentIndex
=
2
;
if
(
currentName
?.
startsWith
(
Routes
.
PROFILE
)
==
true
)
currentIndex
=
1
;
if
(
currentLocation
?.
startsWith
(
Routes
.
PRODUCTS
)
==
true
)
{
currentIndex
=
2
;
}
if
(
currentLocation
?.
startsWith
(
Routes
.
PROFILE
)
==
true
)
{
currentIndex
=
1
;
}
return
Scaffold
(
appBar:
title
==
null
?
null
:
AppBar
(
title:
Text
(
title
),
centerTitle:
true
,
),
body:
GetRouterOutlet
(
emptyPage:
(
delegate
)
=>
DashboardView
(),
pickPages:
(
currentNavStack
)
{
// will take any route after home
final
res
=
currentNavStack
.
pickAfterRoute
(
Routes
.
HOME
);
// print('''RouterOutlet rebuild:
// currentStack: $currentNavStack
// pickedStack: $res''');
final
res
=
currentNavStack
.
currentTreeBranch
.
pickAfterRoute
(
Routes
.
HOME
);
return
res
;
},
),
...
...
@@ -42,7 +34,7 @@ class HomeView extends GetView<HomeController> {
onTap:
(
value
)
{
switch
(
value
)
{
case
0
:
delegate
.
offU
ntil
(
Routes
.
HOME
);
delegate
.
u
ntil
(
Routes
.
HOME
);
break
;
case
1
:
delegate
.
toNamed
(
Routes
.
PROFILE
);
...
...
example_nav2/lib/app/modules/root/bindings/root_binding.dart
0 → 100644
View file @
7a911cf
import
'package:get/get.dart'
;
import
'../controllers/root_controller.dart'
;
class
RootBinding
extends
Bindings
{
@override
void
dependencies
()
{
Get
.
lazyPut
<
RootController
>(
()
=>
RootController
(),
);
}
}
...
...
example_nav2/lib/app/modules/root/controllers/root_controller.dart
0 → 100644
View file @
7a911cf
import
'package:get/get.dart'
;
class
RootController
extends
GetxController
{
//TODO: Implement RootController
final
count
=
0
.
obs
;
@override
void
onInit
()
{
super
.
onInit
();
}
@override
void
onReady
()
{
super
.
onReady
();
}
@override
void
onClose
()
{}
void
increment
()
=>
count
.
value
++;
}
...
...
example_nav2/lib/app/modules/root/views/drawer.dart
0 → 100644
View file @
7a911cf
import
'package:example_nav2/app/routes/app_pages.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
class
DrawerWidget
extends
StatelessWidget
{
const
DrawerWidget
({
Key
?
key
,
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
return
Drawer
(
child:
Column
(
children:
[
Container
(
height:
100
,
color:
Colors
.
red
,
),
ListTile
(
title:
Text
(
'Home'
),
onTap:
()
{
Get
.
getDelegate
()?.
toNamed
(
Routes
.
HOME
);
//to close the drawer
Navigator
.
of
(
context
).
pop
();
},
),
ListTile
(
title:
Text
(
'Settings'
),
onTap:
()
{
Get
.
getDelegate
()?.
toNamed
(
Routes
.
SETTINGS
);
//to close the drawer
Navigator
.
of
(
context
).
pop
();
},
),
],
),
);
}
}
...
...
example_nav2/lib/app/modules/root/views/root_view.dart
0 → 100644
View file @
7a911cf
import
'package:example_nav2/app/routes/app_pages.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'../controllers/root_controller.dart'
;
import
'drawer.dart'
;
class
RootView
extends
GetView
<
RootController
>
{
@override
Widget
build
(
BuildContext
context
)
{
return
GetRouterOutlet
.
builder
(
builder:
(
context
,
rDelegate
,
currentRoute
)
{
final
title
=
currentRoute
?.
location
;
return
Scaffold
(
drawer:
DrawerWidget
(),
appBar:
AppBar
(
title:
Text
(
title
??
''
),
centerTitle:
true
,
),
body:
GetRouterOutlet
(
emptyPage:
(
delegate
)
{
return
Center
(
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Text
(
'<<<< Select something from the drawer on the left'
),
Builder
(
builder:
(
context
)
=>
MaterialButton
(
child:
Icon
(
Icons
.
open_in_new_outlined
),
onPressed:
()
{
Scaffold
.
of
(
context
).
openDrawer
();
},
),
)
],
),
);
},
pickPages:
(
currentNavStack
)
{
//show all routes here except the root view
print
(
'Root RouterOutlet:
$currentNavStack
'
);
return
currentNavStack
.
currentTreeBranch
.
skip
(
1
).
take
(
1
).
toList
();
},
),
);
},
);
}
}
...
...
example_nav2/lib/app/modules/settings/views/settings_view.dart
View file @
7a911cf
...
...
@@ -8,10 +8,6 @@ class SettingsView extends GetView<SettingsController> {
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
title:
Text
(
'SettingsView'
),
centerTitle:
true
,
),
body:
Center
(
child:
Text
(
'SettingsView is working'
,
...
...
example_nav2/lib/app/routes/app_pages.dart
View file @
7a911cf
import
'package:example_nav2/app/modules/root/bindings/root_binding.dart'
;
import
'package:example_nav2/app/modules/root/views/root_view.dart'
;
import
'package:get/get.dart'
;
import
'package:get/get_navigation/src/nav2/router_outlet.dart'
;
import
'../modules/home/bindings/home_binding.dart'
;
...
...
@@ -20,15 +22,21 @@ class AppPages {
static
final
routes
=
[
GetPage
(
name:
'/'
,
page:
()
=>
RootView
(),
middlewares:
[
RouterOutletContainerMiddleWare
(
'/'
),
],
binding:
RootBinding
(),
children:
[
GetPage
(
name:
_Paths
.
HOME
,
preventDuplicates:
true
,
page:
()
=>
HomeView
(),
bindings:
[
HomeBinding
(),
],
title:
null
,
middlewares:
[
RouterOutletContainerMiddleWare
(
_Paths
.
HOME
),
],
children:
[
GetPage
(
name:
_Paths
.
PROFILE
,
...
...
@@ -56,5 +64,7 @@ class AppPages {
page:
()
=>
SettingsView
(),
binding:
SettingsBinding
(),
),
],
),
];
}
...
...
example_nav2/lib/main.dart
View file @
7a911cf
...
...
@@ -10,8 +10,14 @@ void main() {
GetMaterialApp
.
router
(
title:
"Application"
,
getPages:
AppPages
.
routes
,
routeInformationParser:
GetInformationParser
(),
routerDelegate:
GetDelegate
(),
routeInformationParser:
GetInformationParser
(
// initialRoute: Routes.HOME,
),
routerDelegate:
GetDelegate
(
backButtonPopMode:
PopMode
.
History
,
preventDuplicateHandlingMode:
PreventDuplicateHandlingMode
.
PopUntilOriginalRoute
,
),
),
);
}
...
...
lib/get_instance/src/extension_instance.dart
View file @
7a911cf
import
'package:flutter/widgets.dart'
;
import
'package:get/get_navigation/src/nav2/get_router_delegate.dart'
;
import
'../../get_core/src/get_interface.dart'
;
import
'../../route_manager.dart'
;
import
'get_instance.dart'
;
...
...
@@ -130,5 +128,5 @@ extension Inst on GetInterface {
TDelegate
?
delegate
<
TDelegate
extends
RouterDelegate
<
TPage
>,
TPage
>()
=>
routerDelegate
as
TDelegate
?;
GetDelegate
?
getDelegate
()
=>
delegate
<
GetDelegate
,
Get
Page
>();
GetDelegate
?
getDelegate
()
=>
delegate
<
GetDelegate
,
Get
NavConfig
>();
}
...
...
lib/get_navigation/get_navigation.dart
View file @
7a911cf
...
...
@@ -3,6 +3,9 @@ library get_navigation;
export
'src/bottomsheet/bottomsheet.dart'
;
export
'src/extension_navigation.dart'
;
export
'src/nav2/get_information_parser.dart'
;
export
'src/nav2/get_nav_config.dart'
;
export
'src/nav2/get_router_delegate.dart'
;
export
'src/nav2/router_outlet.dart'
;
export
'src/root/get_cupertino_app.dart'
;
export
'src/root/get_material_app.dart'
;
export
'src/root/internacionalization.dart'
;
...
...
lib/get_navigation/src/nav2/get_information_parser.dart
View file @
7a911cf
...
...
@@ -2,28 +2,44 @@ import 'package:flutter/foundation.dart';
import
'package:flutter/widgets.dart'
;
import
'../../../get.dart'
;
class
GetInformationParser
extends
RouteInformationParser
<
GetPage
>
{
class
GetInformationParser
extends
RouteInformationParser
<
GetNavConfig
>
{
final
String
initialRoute
;
GetInformationParser
({
this
.
initialRoute
=
'/'
,
});
@override
SynchronousFuture
<
Get
Page
>
parseRouteInformation
(
SynchronousFuture
<
Get
NavConfig
>
parseRouteInformation
(
RouteInformation
routeInformation
,
)
{
if
(
routeInformation
.
location
==
'/'
)
{
return
SynchronousFuture
(
Get
.
routeTree
.
routes
.
first
);
print
(
'GetInformationParser: route location:
${routeInformation.location}
'
);
var
location
=
routeInformation
.
location
;
if
(
location
==
'/'
)
{
//check if there is a corresponding page
//if not, relocate to initialRoute
if
(!
Get
.
routeTree
.
routes
.
any
((
element
)
=>
element
.
name
==
'/'
))
{
location
=
initialRoute
;
}
}
print
(
'route location:
${routeInformation.location}
'
);
final
page
=
Get
.
routeTree
.
matchRoute
(
routeInformation
.
location
!);
print
(
page
.
parameters
);
final
val
=
page
.
route
!.
copy
(
name:
routeInformation
.
location
,
parameter:
Map
.
from
(
page
.
parameters
),
final
matchResult
=
Get
.
routeTree
.
matchRoute
(
location
??
initialRoute
);
return
SynchronousFuture
(
GetNavConfig
(
currentTreeBranch:
matchResult
.
treeBranch
,
location:
location
,
state:
routeInformation
.
state
,
),
);
return
SynchronousFuture
(
val
);
}
@override
RouteInformation
restoreRouteInformation
(
GetPage
uri
)
{
print
(
'restore
$uri
'
);
RouteInformation
restoreRouteInformation
(
GetNavConfig
config
)
{
print
(
'restore
$config
'
);
return
RouteInformation
(
location:
uri
.
name
);
return
RouteInformation
(
location:
config
.
location
,
state:
config
.
state
,
);
}
}
...
...
lib/get_navigation/src/nav2/get_nav_config.dart
0 → 100644
View file @
7a911cf
import
'package:flutter/widgets.dart'
;
import
'package:get/get.dart'
;
/// This config enables us to navigate directly to a sub-url
class
GetNavConfig
extends
RouteInformation
{
final
List
<
GetPage
>
currentTreeBranch
;
GetPage
?
get
currentPage
=>
currentTreeBranch
.
last
;
GetNavConfig
({
required
this
.
currentTreeBranch
,
required
String
?
location
,
required
Object
?
state
,
})
:
super
(
location:
location
,
state:
state
,
);
GetNavConfig
copyWith
({
List
<
GetPage
>?
currentTreeBranch
,
GetPage
?
currentPage
,
required
String
?
location
,
required
Object
?
state
,
})
{
return
GetNavConfig
(
currentTreeBranch:
currentTreeBranch
??
this
.
currentTreeBranch
,
location:
location
??
this
.
location
,
state:
state
??
this
.
state
,
);
}
@override
String
toString
()
=>
'''
======GetNavConfig=====
currentTreeBranch:
$currentTreeBranch
currentPage:
$currentPage
======GetNavConfig====='''
;
}
...
...
lib/get_navigation/src/nav2/get_router_delegate.dart
View file @
7a911cf
import
'dart:async'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get_navigation/src/nav2/router_outlet.dart'
;
import
'../../../get.dart'
;
import
'../../../get_state_manager/src/simple/list_notifier.dart'
;
class
GetDelegate
extends
RouterDelegate
<
GetPage
>
with
ListenableMixin
,
ListNotifierMixin
{
final
List
<
GetPage
>
routes
=
<
GetPage
>[];
/// Enables the user to customize the intended pop behavior
///
/// Goes to either the previous history 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 history stack will be:
/// 1) /home
///
/// when popping on [Page] mode, it will only remove the last part of the route
/// so the new history stack will be:
/// 1) /home
/// 2) /home/products
///
/// another pop will change the history 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 history entries until it reaches the old route
PopUntilOriginalRoute
,
final
pageRoutes
=
<
GetPage
,
GetPageRoute
>{};
/// Simply don't push the new route
DoNothing
,
}
class
GetDelegate
extends
RouterDelegate
<
GetNavConfig
>
with
ListenableMixin
,
ListNotifierMixin
{
final
List
<
GetNavConfig
>
history
=
<
GetNavConfig
>[];
final
PopMode
backButtonPopMode
;
final
PreventDuplicateHandlingMode
preventDuplicateHandlingMode
;
final
pageRoutes
=
<
String
,
GetPageRoute
>{};
GetPage
?
notFoundRoute
;
final
List
<
NavigatorObserver
>?
dipNav
Observers
;
final
List
<
NavigatorObserver
>?
navigator
Observers
;
final
TransitionDelegate
<
dynamic
>?
transitionDelegate
;
final
_resultCompleter
=
<
GetNavConfig
,
Completer
<
Object
?>>{};
GlobalKey
<
NavigatorState
>
get
navigatorKey
=>
GetNavigation
.
getxController
.
key
;
GetDelegate
(
{
this
.
notFoundRoute
,
this
.
dipNavObservers
,
this
.
transitionDelegate
});
GetDelegate
({
this
.
notFoundRoute
,
this
.
navigatorObservers
,
this
.
transitionDelegate
,
this
.
backButtonPopMode
=
PopMode
.
History
,
this
.
preventDuplicateHandlingMode
=
PreventDuplicateHandlingMode
.
DoNothing
,
});
/// Adds a new history entry and waits for the result
Future
<
T
?>
pushHistory
<
T
>(
GetNavConfig
config
,
{
bool
rebuildStack
=
true
,
})
{
//this changes the currentConfiguration
final
completer
=
Completer
<
T
?>();
_resultCompleter
[
config
]
=
completer
;
_pushHistory
(
config
);
if
(
rebuildStack
)
{
refresh
();
}
return
completer
.
future
;
}
void
_removeHistoryEntry
(
GetNavConfig
entry
)
{
history
.
remove
(
entry
);
pageRoutes
.
remove
(
entry
.
location
);
final
lastCompleter
=
_resultCompleter
.
remove
(
entry
);
lastCompleter
?.
complete
(
entry
);
}
void
_pushHistory
(
GetNavConfig
config
)
{
if
(
config
.
currentPage
!.
preventDuplicates
)
{
if
(
history
.
any
((
element
)
=>
element
.
location
==
config
.
location
))
{
switch
(
preventDuplicateHandlingMode
)
{
case
PreventDuplicateHandlingMode
.
PopUntilOriginalRoute
:
until
(
config
.
location
!,
popMode:
PopMode
.
History
);
return
;
case
PreventDuplicateHandlingMode
.
DoNothing
:
default
:
return
;
}
}
}
history
.
add
(
config
);
pageRoutes
[
config
.
location
!]
=
PageRedirect
(
config
.
currentPage
!,
_notFound
()).
page
();
}
GetNavConfig
?
_popHistory
()
{
if
(!
_canPopHistory
())
return
null
;
return
_doPopHistory
();
}
GetNavConfig
_doPopHistory
()
{
final
res
=
history
.
removeLast
();
pageRoutes
.
remove
(
res
.
location
);
return
res
;
}
GetNavConfig
?
_popPage
()
{
if
(!
_canPopPage
())
return
null
;
return
_doPopPage
();
}
GetNavConfig
?
_pop
(
PopMode
mode
)
{
switch
(
mode
)
{
case
PopMode
.
History
:
return
_popHistory
();
case
PopMode
.
Page
:
return
_popPage
();
default
:
return
null
;
}
}
// returns the popped page
GetNavConfig
?
_doPopPage
()
{
final
currentBranch
=
currentConfiguration
?.
currentTreeBranch
;
if
(
currentBranch
!=
null
&&
currentBranch
.
length
>
1
)
{
//remove last part only
final
remaining
=
currentBranch
.
take
(
currentBranch
.
length
-
1
);
final
prevHistoryEntry
=
history
.
length
>
1
?
history
[
history
.
length
-
2
]
:
null
;
//check if current route is the same as the previous route
if
(
prevHistoryEntry
!=
null
)
{
//if so, pop the entire history entry
final
newLocation
=
remaining
.
last
.
name
;
final
prevLocation
=
prevHistoryEntry
.
location
;
if
(
newLocation
==
prevLocation
)
{
//pop the entire history entry
return
_popHistory
();
}
}
//create a new route with the remaining tree branch
final
res
=
_popHistory
();
_pushHistory
(
GetNavConfig
(
currentTreeBranch:
remaining
.
toList
(),
location:
remaining
.
last
.
name
,
state:
null
,
//TOOD: persist state??
),
);
return
res
;
}
else
{
//remove entire entry
return
_popHistory
();
}
}
Future
<
GetNavConfig
?>
popHistory
()
{
return
SynchronousFuture
(
_popHistory
());
}
bool
_canPopHistory
()
{
return
history
.
length
>
1
;
}
Future
<
bool
>
canPopHistory
()
{
return
SynchronousFuture
(
_canPopHistory
());
}
List
<
GetPage
>
getVisiblePages
()
{
return
routes
.
where
((
r
)
{
bool
_canPopPage
()
{
final
currentTreeBranch
=
currentConfiguration
?.
currentTreeBranch
;
if
(
currentTreeBranch
==
null
)
return
false
;
return
currentTreeBranch
.
length
>
1
?
true
:
_canPopHistory
();
}
Future
<
bool
>
canPopPage
()
{
return
SynchronousFuture
(
_canPopPage
());
}
/// gets the visual pages from the current history entry
///
/// visual pages must have the [RouterOutletContainerMiddleWare] middleware
/// with `stayAt` equal to the route name of the visual page
List
<
GetPage
>
getVisualPages
()
{
final
currentHistory
=
currentConfiguration
;
if
(
currentHistory
==
null
)
return
<
GetPage
>[];
return
currentHistory
.
currentTreeBranch
.
where
((
r
)
{
final
mware
=
(
r
.
middlewares
??
[]).
whereType
<
RouterOutletContainerMiddleWare
>();
if
(
mware
.
length
==
0
)
return
true
;
...
...
@@ -31,65 +205,77 @@ class GetDelegate extends RouterDelegate<GetPage>
}).
toList
();
}
/// Called by the [Router] at startup with the structure that the
/// [RouteInformationParser] obtained from parsing the initial route.
@override
Widget
build
(
BuildContext
context
)
{
final
pages
=
getVisiblePages
();
final
pages
=
getVisualPages
();
final
extraObservers
=
navigatorObservers
;
return
Navigator
(
key:
navigatorKey
,
onPopPage:
_onPop
Pag
e
,
onPopPage:
_onPop
VisualRout
e
,
pages:
pages
,
observers:
[
GetObserver
(),
if
(
extraObservers
!=
null
)
...
extraObservers
,
],
transitionDelegate:
transitionDelegate
??
const
DefaultTransitionDelegate
<
dynamic
>(),
);
}
final
_resultCompleter
=
<
GetPage
,
Completer
<
Object
?>>{};
@override
Future
<
void
>
setInitialRoutePath
(
GetPage
configuration
)
async
{
await
pushRoute
(
configuration
);
Future
<
void
>
setInitialRoutePath
(
GetNavConfig
configuration
)
async
{
history
.
clear
();
pageRoutes
.
clear
();
_resultCompleter
.
clear
();
await
pushHistory
(
configuration
);
}
@override
Future
<
void
>
setNewRoutePath
(
GetPage
configuration
)
{
/// incorrect, remove routes until you reach the page in configuration.
/// if it's not found push it.
routes
.
clear
();
pageRoutes
.
clear
();
return
pushRoute
(
configuration
);
Future
<
void
>
setNewRoutePath
(
GetNavConfig
configuration
)
async
{
await
pushHistory
(
configuration
);
}
/// Called by the [Router] when it detects a route information may have
/// changed as a result of rebuild.
@override
GetPage
get
currentConfiguration
{
final
route
=
routes
.
last
;
GetNavConfig
?
get
currentConfiguration
{
if
(
history
.
isEmpty
)
return
null
;
final
route
=
history
.
last
;
return
route
;
}
GetPageRoute
?
get
currentRoute
=>
pageRoutes
[
currentConfiguration
];
Future
<
T
?>
toNamed
<
T
>(
String
route
)
{
final
page
=
Get
.
routeTree
.
matchRoute
(
route
);
if
(
page
.
route
!=
null
)
{
return
pushRoute
(
page
.
route
!.
copy
(
name:
route
));
}
else
{
return
pushRoute
(
_notFound
());
GetPageRoute
?
get
currentRoute
{
final
curPage
=
currentConfiguration
?.
currentPage
;
return
curPage
==
null
?
null
:
pageRoutes
[
curPage
];
}
Future
<
T
?>
toNamed
<
T
>(
String
fullRoute
)
{
final
decoder
=
Get
.
routeTree
.
matchRoute
(
fullRoute
);
return
pushHistory
<
T
>(
GetNavConfig
(
currentTreeBranch:
decoder
.
treeBranch
,
location:
fullRoute
,
state:
null
,
//TODO: persist state?
),
);
}
Future
<
T
?>
offUntil
<
T
>(
String
route
)
{
final
page
=
Get
.
routeTree
.
matchRoute
(
route
);
if
(
page
.
route
!=
null
)
{
return
pushRoute
(
page
.
route
!.
copy
(
name:
route
),
removeUntil:
true
);
}
else
{
return
pushRoute
(
_notFound
());
/// Removes routes according to [PopMode]
/// until it reaches the specifc [fullRoute],
/// DOES NOT remove the [fullRoute]
void
until
(
String
fullRoute
,
{
PopMode
popMode
=
PopMode
.
History
,
})
{
// remove history or page entries until you meet route
final
currentEntry
=
currentConfiguration
;
var
iterator
=
currentEntry
;
while
(
history
.
length
>
0
&&
iterator
!=
null
&&
iterator
.
location
!=
fullRoute
)
{
_pop
(
popMode
);
// replace iterator
iterator
=
currentConfiguration
;
}
refresh
();
}
GetPage
_notFound
()
{
...
...
@@ -101,33 +287,6 @@ class GetDelegate extends RouterDelegate<GetPage>
);
}
Future
<
T
?>
pushRoute
<
T
>(
GetPage
page
,
{
bool
removeUntil
=
false
,
bool
replaceCurrent
=
false
,
bool
rebuildStack
=
true
,
})
{
final
completer
=
Completer
<
T
?>();
_resultCompleter
[
page
]
=
completer
;
page
=
page
.
copy
(
unknownRoute:
_notFound
());
assert
(!(
removeUntil
&&
replaceCurrent
),
'Only removeUntil or replaceCurrent should by true!'
);
if
(
removeUntil
)
{
routes
.
clear
();
pageRoutes
.
clear
();
}
else
if
(
replaceCurrent
&&
routes
.
isNotEmpty
)
{
final
lastPage
=
routes
.
removeLast
();
pageRoutes
.
remove
(
lastPage
);
}
addPage
(
page
);
if
(
rebuildStack
)
{
refresh
();
}
//emulate the old push with result
return
completer
.
future
;
}
Future
<
bool
>
handlePopupRoutes
({
Object
?
result
,
})
async
{
...
...
@@ -145,79 +304,38 @@ class GetDelegate extends RouterDelegate<GetPage>
@override
Future
<
bool
>
popRoute
({
Object
?
result
,
PopMode
popMode
=
PopMode
.
History
,
})
async
{
//Returning false will cause the entire app to be popped.
final
wasPopup
=
await
handlePopupRoutes
(
result:
result
);
if
(
wasPopup
)
return
true
;
if
(
canPop
())
{
final
_popped
=
_pop
(
popMode
);
refresh
();
if
(
_popped
!=
null
)
{
//emulate the old pop with result
final
lastRoute
=
routes
.
last
;
final
lastCompleter
=
_resultCompleter
.
remove
(
lastRoute
);
final
lastCompleter
=
_resultCompleter
.
remove
(
_popped
);
lastCompleter
?.
complete
(
result
);
//route to be removed
removePage
(
lastRoute
);
return
Future
.
value
(
true
);
}
return
Future
.
value
(
false
);
}
bool
canPop
()
{
return
routes
.
length
>
1
;
}
bool
_onPopPage
(
Route
<
dynamic
>
route
,
dynamic
result
)
{
bool
_onPopVisualRoute
(
Route
<
dynamic
>
route
,
dynamic
result
)
{
final
didPop
=
route
.
didPop
(
result
);
if
(!
didPop
)
{
return
false
;
}
final
settings
=
route
.
settings
;
if
(
settings
is
GetPage
)
{
removePage
(
settings
);
}
refresh
();
return
true
;
}
void
removePage
(
GetPage
page
)
{
final
isLast
=
routes
.
last
==
page
;
//check if it's last
routes
.
remove
(
page
);
final
oldPageRoute
=
pageRoutes
.
remove
(
page
);
if
(
isLast
&&
oldPageRoute
!=
null
)
{
_currentRoutePopped
(
oldPageRoute
);
final
newPageRoute
=
pageRoutes
[
routes
.
last
];
if
(
newPageRoute
!=
null
)
_currentRouteChanged
(
newPageRoute
);
}
refresh
();
}
void
addPage
(
GetPage
route
)
{
routes
.
add
(
route
,
final
config
=
history
.
cast
<
GetNavConfig
?>().
firstWhere
(
(
element
)
=>
element
?.
currentPage
==
settings
,
orElse:
()
=>
null
,
);
final
pageRoute
=
pageRoutes
[
route
]
=
PageRedirect
(
route
,
_notFound
()).
page
();
_currentRouteChanged
(
pageRoute
);
refresh
();
if
(
config
!=
null
)
{
_removeHistoryEntry
(
config
);
}
void
addRoutes
(
List
<
GetPage
>
pages
)
{
routes
.
addAll
(
pages
);
for
(
var
item
in
pages
)
{
pageRoutes
[
item
]
=
PageRedirect
(
item
,
_notFound
()).
page
();
}
final
pageRoute
=
pageRoutes
[
routes
.
last
];
if
(
pageRoute
!=
null
)
_currentRouteChanged
(
pageRoute
);
refresh
();
}
void
_currentRoutePopped
(
GetPageRoute
route
)
{
route
.
dispose
();
}
void
_currentRouteChanged
(
GetPageRoute
route
)
{
//is this method useful ?
//transition? -> in router outlet ??
//buildPage? -> in router outlet
return
true
;
}
}
...
...
lib/get_navigation/src/nav2/router_outlet.dart
View file @
7a911cf
...
...
@@ -20,16 +20,21 @@ class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
RouterOutlet
({
TDelegate
?
delegate
,
required
List
<
T
>
Function
(
TDelegate
routerDelegate
)
currentNavStack
,
required
List
<
T
>
Function
(
List
<
T
>
currentNavStack
)
pickPages
,
required
Widget
Function
(
BuildContext
context
,
TDelegate
,
T
?
page
)
required
List
<
RouteSettings
>
Function
(
T
currentNavStack
)
pickPages
,
required
Widget
Function
(
BuildContext
context
,
TDelegate
,
RouteSettings
?
page
,
)
pageBuilder
,
})
:
this
.
builder
(
builder:
(
context
,
rDelegate
,
currentConfig
)
{
final
currentStack
=
currentNavStack
(
rDelegate
);
final
picked
=
pickPages
(
currentStack
);
if
(
picked
.
length
==
0
)
final
picked
=
currentConfig
==
null
?
<
RouteSettings
>[]
:
pickPages
(
currentConfig
);
if
(
picked
.
length
==
0
)
{
return
pageBuilder
(
context
,
rDelegate
,
null
);
}
return
pageBuilder
(
context
,
rDelegate
,
picked
.
last
);
},
delegate:
delegate
,
...
...
@@ -68,12 +73,12 @@ class _RouterOutletState<TDelegate extends RouterDelegate<T>, T extends Object>
}
}
class
GetRouterOutlet
extends
RouterOutlet
<
GetDelegate
,
Get
Page
>
{
class
GetRouterOutlet
extends
RouterOutlet
<
GetDelegate
,
Get
NavConfig
>
{
GetRouterOutlet
.
builder
({
required
Widget
Function
(
BuildContext
context
,
GetDelegate
delegate
,
Get
Page
?
currentRoute
,
Get
NavConfig
?
currentRoute
,
)
builder
,
GetDelegate
?
routerDelegate
,
...
...
@@ -84,10 +89,10 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetPage> {
GetRouterOutlet
({
Widget
Function
(
GetDelegate
delegate
)?
emptyPage
,
required
List
<
GetPage
>
Function
(
List
<
GetPage
>
currentNavStack
)
pickPages
,
required
List
<
GetPage
>
Function
(
GetNavConfig
currentNavStack
)
pickPages
,
})
:
super
(
pageBuilder:
(
context
,
rDelegate
,
page
)
{
final
pageRoute
=
rDelegate
.
pageRoutes
[
page
];
final
pageRoute
=
rDelegate
.
pageRoutes
[
page
?.
name
];
if
(
pageRoute
!=
null
)
{
//TODO: transitions go here !
return
pageRoute
.
buildPage
(
...
...
@@ -102,21 +107,18 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, GetPage> {
rDelegate
.
notFoundRoute
?.
page
())
??
SizedBox
.
shrink
();
},
currentNavStack:
(
routerDelegate
)
=>
routerDelegate
.
routes
,
pickPages:
pickPages
,
delegate:
Get
.
getDelegate
(),
);
}
/// A marker outlet to identify which pages are visual
/// (handled by the navigator) and which are logical
/// (handled by the delegate)
class
RouterOutletContainerMiddleWare
extends
GetMiddleware
{
final
String
stayAt
;
RouterOutletContainerMiddleWare
(
this
.
stayAt
);
// @override
// RouteSettings? redirect(String? route) {
// print('RouterOutletContainerMiddleWare: Redirect called ($route)');
// return null;
// }
}
extension
PagesListExt
on
List
<
GetPage
>
{
...
...
lib/get_navigation/src/root/parse_route.dart
View file @
7a911cf
import
'../../../get_core/src/get_main.dart'
;
import
'../../get_navigation.dart'
;
import
'../routes/get_route.dart'
;
class
RouteDecoder
{
final
GetPage
?
route
;
final
Map
<
String
,
String
?>
parameters
;
const
RouteDecoder
(
this
.
route
,
this
.
parameters
);
final
List
<
GetPage
>
treeBranch
;
GetPage
?
get
route
=>
treeBranch
.
isEmpty
?
null
:
treeBranch
.
last
;
final
Map
<
String
,
String
>
parameters
;
const
RouteDecoder
(
this
.
treeBranch
,
this
.
parameters
,
);
}
class
ParseRouteTree
{
...
...
@@ -17,20 +20,61 @@ class ParseRouteTree {
RouteDecoder
matchRoute
(
String
name
)
{
final
uri
=
Uri
.
parse
(
name
);
final
route
=
_findRoute
(
uri
.
path
);
final
params
=
Map
<
String
,
String
?>.
from
(
uri
.
queryParameters
);
if
(
route
!=
null
)
{
final
parsedParams
=
_parseParams
(
name
,
route
.
path
);
// /home/profile/123 => home,profile,123 => /,/home,/home/profile,/home/profile/123
final
split
=
uri
.
path
.
split
(
'/'
).
where
((
element
)
=>
element
.
isNotEmpty
);
var
curPath
=
'/'
;
final
cumulativePaths
=
<
String
>[
'/'
,
];
for
(
var
item
in
split
)
{
if
(
curPath
.
endsWith
(
'/'
))
{
curPath
+=
'
$item
'
;
}
else
{
curPath
+=
'/
$item
'
;
}
cumulativePaths
.
add
(
curPath
);
}
final
treeBranch
=
cumulativePaths
.
map
(
(
p
)
{
final
res
=
_findRoute
(
p
);
//change GetPage name from the regex to the actual name
return
res
?.
copy
(
name:
p
,
);
},
)
.
where
((
element
)
=>
element
!=
null
)
.
cast
<
GetPage
>()
.
toList
();
final
params
=
Map
<
String
,
String
>.
from
(
uri
.
queryParameters
);
if
(
treeBranch
.
isNotEmpty
)
{
//route is found, do further parsing to get nested query params
final
lastRoute
=
treeBranch
.
last
;
final
parsedParams
=
_parseParams
(
name
,
lastRoute
.
path
);
if
(
parsedParams
.
isNotEmpty
)
{
params
.
addAll
(
parsedParams
);
}
//copy parameters to all pages.
final
mappedTreeBranch
=
treeBranch
.
map
(
(
e
)
=>
e
.
copy
(
parameter:
params
,
),
)
.
toList
();
return
RouteDecoder
(
mappedTreeBranch
,
params
,
);
}
// This logger sends confusing messages
// else {
// // Get.log('Route "${uri.path}" not found');
// }
return
RouteDecoder
(
route
,
params
);
//route not found
return
RouteDecoder
(
treeBranch
,
params
,
);
}
void
addRoutes
(
List
<
GetPage
>
getPages
)
{
...
...
@@ -99,8 +143,8 @@ class ParseRouteTree {
);
}
Map
<
String
,
String
?>
_parseParams
(
String
path
,
PathDecoded
routePath
)
{
final
params
=
<
String
,
String
?>{};
Map
<
String
,
String
>
_parseParams
(
String
path
,
PathDecoded
routePath
)
{
final
params
=
<
String
,
String
>{};
var
idx
=
path
.
indexOf
(
'?'
);
if
(
idx
>
-
1
)
{
path
=
path
.
substring
(
0
,
idx
);
...
...
lib/get_navigation/src/routes/get_route.dart
View file @
7a911cf
...
...
@@ -41,7 +41,7 @@ class GetPage<T> extends Page<T> {
final
CustomTransition
?
customTransition
;
final
Duration
?
transitionDuration
;
final
bool
fullscreenDialog
;
final
bool
preventDuplicates
;
// @override
// final LocalKey? key;
...
...
@@ -79,6 +79,7 @@ class GetPage<T> extends Page<T> {
this
.
children
,
this
.
middlewares
,
this
.
unknownRoute
,
this
.
preventDuplicates
=
false
,
})
:
path
=
_nameToRegex
(
name
),
super
(
key:
ValueKey
(
name
),
...
...
@@ -128,8 +129,10 @@ class GetPage<T> extends Page<T> {
List
<
GetPage
>?
children
,
GetPage
?
unknownRoute
,
List
<
GetMiddleware
>?
middlewares
,
bool
?
preventDuplicates
,
})
{
return
GetPage
(
preventDuplicates:
preventDuplicates
??
this
.
preventDuplicates
,
name:
name
??
this
.
name
,
page:
page
??
this
.
page
,
popGesture:
popGesture
??
this
.
popGesture
,
...
...
@@ -145,7 +148,6 @@ class GetPage<T> extends Page<T> {
customTransition:
customTransition
??
this
.
customTransition
,
transitionDuration:
transitionDuration
??
this
.
transitionDuration
,
fullscreenDialog:
fullscreenDialog
??
this
.
fullscreenDialog
,
// settings: settings ?? this.settings,
children:
children
??
this
.
children
,
unknownRoute:
unknownRoute
??
this
.
unknownRoute
,
middlewares:
middlewares
??
this
.
middlewares
,
...
...
@@ -171,6 +173,8 @@ class GetPage<T> extends Page<T> {
other
.
page
.
runtimeType
==
page
.
runtimeType
&&
other
.
popGesture
==
popGesture
&&
// mapEquals(other.parameter, parameter) &&
other
.
preventDuplicates
==
preventDuplicates
&&
other
.
title
==
title
&&
other
.
transition
==
transition
&&
other
.
curve
==
curve
&&
...
...
@@ -194,6 +198,7 @@ class GetPage<T> extends Page<T> {
return
//page.hashCode ^
popGesture
.
hashCode
^
// parameter.hashCode ^
preventDuplicates
.
hashCode
^
title
.
hashCode
^
transition
.
hashCode
^
curve
.
hashCode
^
...
...
Please
register
or
login
to post a comment