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-07-31 22:00:02 +0100
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
347dd505dc1884d0bbee42a7f08c76fb242da470
347dd505
1 parent
eb99b189
fix microtask and routes
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
529 additions
and
333 deletions
example/test/main_test.dart
lib/get_core/src/typedefs.dart
lib/get_instance/src/extension_instance.dart
lib/get_navigation/src/extension_navigation.dart
lib/get_navigation/src/routes/get_information_parser.dart
lib/get_navigation/src/routes/get_route.dart
lib/get_navigation/src/routes/get_router_delegate.dart
lib/get_navigation/src/routes/modules.dart
lib/get_navigation/src/routes/parse_route.dart
lib/get_navigation/src/routes/route_middleware.dart
lib/get_navigation/src/routes/router_outlet.dart
lib/get_state_manager/src/rx_flutter/rx_notifier.dart
lib/get_state_manager/src/simple/list_notifier.dart
lib/get_state_manager/src/simple/simple_builder.dart
lib/get_utils/get_utils.dart
lib/get_utils/src/equality/equality.dart
test/instance/get_instance_test.dart
test/navigation/parse_route_test.dart
test/state_manager/get_obx_test.dart
example/test/main_test.dart
View file @
347dd50
...
...
@@ -7,14 +7,11 @@ import 'package:get/get.dart';
// import 'package:get_test/get_test.dart';
import
'package:matcher/matcher.dart'
as
m
;
import
'../lib/pages/home/domain/adapters/repository_adapter.dart'
;
import
'../lib/pages/home/domain/entity/cases_model.dart'
;
import
'../lib/pages/home/presentation/controllers/home_controller.dart'
;
class
MockRepositorySuccess
implements
IHomeRepository
{
@override
Future
<
CasesModel
>
getCases
()
async
{
return
CasesModel
(
...
...
lib/get_core/src/typedefs.dart
View file @
347dd50
typedef
ValueUpdater
<
T
>
=
T
Function
();
/// This allows a value of type T or T?
/// to be treated as a value of type T?.
///
...
...
lib/get_instance/src/extension_instance.dart
View file @
347dd50
...
...
@@ -47,27 +47,6 @@ extension Inst on GetInterface {
// );
// }
/// async version of `Get.put()`.
/// Awaits for the resolution of the Future from `builder()` parameter and
/// stores the Instance returned.
Future
<
S
>
putAsync
<
S
>(
AsyncInstanceBuilderCallback
<
S
>
builder
,
{
String
?
tag
,
bool
permanent
=
false
,
})
async
{
return
put
<
S
>(
await
builder
(),
tag:
tag
,
permanent:
permanent
);
}
/// Injects an instance `<S>` in memory to be globally accessible.
///
/// No need to define the generic type `<S>` as it's inferred from
/// the [dependency]
///
/// - [dependency] The Instance to be injected.
/// - [tag] optionally, use a [tag] as an "id" to create multiple records of
/// the same Type<[S]>
/// - [permanent] keeps the Instance in memory, not following
/// `Get.smartManagement` rules.
S
put
<
S
>(
S
dependency
,
{
String
?
tag
,
...
...
lib/get_navigation/src/extension_navigation.dart
View file @
347dd50
...
...
@@ -1253,8 +1253,6 @@ extension GetNavigationExt on GetInterface {
set
parameters
(
Map
<
String
,
String
?>
newParameters
)
=>
_getxController
.
parameters
=
newParameters
;
bool
get
testMode
=>
_getxController
.
testMode
;
set
testMode
(
bool
isTest
)
=>
_getxController
.
testMode
=
isTest
;
...
...
lib/get_navigation/src/routes/get_information_parser.dart
View file @
347dd50
...
...
@@ -19,7 +19,8 @@ class GetInformationParser extends RouteInformationParser<RouteDecoder> {
if
(
location
==
'/'
)
{
//check if there is a corresponding page
//if not, relocate to initialRoute
if
(!(
Get
.
rootController
.
routerDelegate
as
GetDelegate
).
registeredRoutes
if
(!(
Get
.
rootController
.
routerDelegate
as
GetDelegate
)
.
registeredRoutes
.
any
((
element
)
=>
element
.
name
==
'/'
))
{
location
=
initialRoute
;
}
...
...
lib/get_navigation/src/routes/get_route.dart
View file @
347dd50
...
...
@@ -45,7 +45,7 @@ class GetPage<T> extends Page<T> {
final
List
<
GetPage
>
children
;
final
List
<
GetMiddleware
>?
middlewares
;
//
final PathDecoded path;
final
PathDecoded
path
;
final
GetPage
?
unknownRoute
;
final
bool
showCupertinoParallax
;
...
...
@@ -82,7 +82,7 @@ class GetPage<T> extends Page<T> {
PreventDuplicateHandlingMode
.
reorderRoutes
,
this
.
completer
,
LocalKey
?
key
,
})
:
//
path = _nameToRegex(name),
})
:
path
=
_nameToRegex
(
name
),
assert
(
name
.
startsWith
(
'/'
),
'It is necessary to start route name [
$name
] with a slash: /
$name
'
),
super
(
...
...
@@ -168,26 +168,26 @@ class GetPage<T> extends Page<T> {
return
_page
;
}
// static PathDecoded _nameToRegex(String path) {
// var keys = <String?>[];
static
PathDecoded
_nameToRegex
(
String
path
)
{
var
keys
=
<
String
?>[];
// String _replace(Match pattern) {
// var buffer = StringBuffer('(?:');
String
_replace
(
Match
pattern
)
{
var
buffer
=
StringBuffer
(
'(?:'
);
// if (pattern[1] != null) buffer.write('.');
// buffer.write('([\\w%+-._~!\$&\'()*,;=:@]+))');
// if (pattern[3] != null) buffer.write('?');
if
(
pattern
[
1
]
!=
null
)
buffer
.
write
(
'.'
);
buffer
.
write
(
'([
\\
w%+-._~!
\$
&
\'
()*,;=:@]+))'
);
if
(
pattern
[
3
]
!=
null
)
buffer
.
write
(
'?'
);
// keys.add(pattern[2]);
// return "$buffer";
// }
keys
.
add
(
pattern
[
2
]);
return
"
$buffer
"
;
}
// var stringPath = '$path/?'
// .replaceAllMapped(RegExp(r'(\.)?:(\w+)(\?)?'), _replace)
// .replaceAll('//', '/');
var
stringPath
=
'
$path
/?'
.
replaceAllMapped
(
RegExp
(
r'(\.)?:(\w+)(\?)?'
),
_replace
)
.
replaceAll
(
'//'
,
'/'
);
// return PathDecoded(RegExp('^$stringPath\$'), keys);
// }
return
PathDecoded
(
RegExp
(
'^
$stringPath
\$
'
),
keys
);
}
@override
bool
operator
==(
Object
other
)
{
...
...
@@ -205,20 +205,20 @@ class GetPage<T> extends Page<T> {
}
}
// @immutable
// class PathDecoded {
// final RegExp regex;
// final List<String?> keys;
// const PathDecoded(this.regex, this.keys);
@immutable
class
PathDecoded
{
final
RegExp
regex
;
final
List
<
String
?>
keys
;
const
PathDecoded
(
this
.
regex
,
this
.
keys
);
// @override
// int get hashCode => regex.hashCode;
@override
int
get
hashCode
=>
regex
.
hashCode
;
// @override
// bool operator ==(Object other) {
// if (identical(this, other)) return true;
@override
bool
operator
==(
Object
other
)
{
if
(
identical
(
this
,
other
))
return
true
;
// return other is PathDecoded &&
// other.regex == regex; // && listEquals(other.keys, keys);
// }
// }
return
other
is
PathDecoded
&&
other
.
regex
==
regex
;
// && listEquals(other.keys, keys);
}
}
...
...
lib/get_navigation/src/routes/get_router_delegate.dart
View file @
347dd50
...
...
@@ -26,31 +26,28 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
List
<
RouteDecoder
>
get
activePages
=>
_activePages
;
final
_routeTree
=
ParseRouteTree
();
final
_routeTree
=
ParseRouteTree
(
routes:
[]
);
final
List
<
GetPage
>
_routes
=
[];
List
<
GetPage
>
get
registeredRoutes
=>
_routes
;
List
<
GetPage
>
get
registeredRoutes
=>
_routeTree
.
routes
;
void
addPages
(
List
<
GetPage
>
getPages
)
{
_route
s
.
addRoutes
(
getPages
);
_route
Tree
.
addRoutes
(
getPages
);
}
void
clearRouteTree
()
{
_routes
.
clear
();
_route
Tree
.
route
s
.
clear
();
}
void
addPage
(
GetPage
getPage
)
{
_route
s
.
addRoute
(
getPage
);
_route
Tree
.
addRoute
(
getPage
);
}
void
removePage
(
GetPage
getPage
)
{
_route
s
.
removeRoute
(
getPage
);
_route
Tree
.
removeRoute
(
getPage
);
}
RouteDecoder
?
matchRoute
(
String
name
,
{
PageSettings
?
arguments
})
{
final
settings
=
_buildPageSettings
(
name
,
arguments
);
return
_getRouteDecoder
(
settings
);
RouteDecoder
matchRoute
(
String
name
,
{
PageSettings
?
arguments
})
{
return
_routeTree
.
matchRoute
(
name
,
arguments:
arguments
);
}
// GlobalKey<NavigatorState> get navigatorKey => Get.key;
...
...
@@ -141,9 +138,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
}
Map
<
String
,
String
>
get
parameters
{
return
currentConfiguration
?.
route
?.
parameters
??
// currentConfiguration?.pageSettings?.params ??
{};
return
currentConfiguration
?.
pageSettings
?.
params
??
{};
}
PageSettings
?
get
pageSettings
{
...
...
@@ -365,7 +360,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
})
async
{
routeName
=
_cleanRouteName
(
"/
${page.runtimeType}
"
);
// if (preventDuplicateHandlingMode ==
//
PreventDuplicateHandlingMode.Recreate) {
//PreventDuplicateHandlingMode.Recreate) {
// routeName = routeName + page.hashCode.toString();
// }
...
...
@@ -384,14 +379,14 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
preventDuplicateHandlingMode:
preventDuplicateHandlingMode
,
);
_route
s
.
addRoute
(
getPage
);
_route
Tree
.
addRoute
(
getPage
);
final
args
=
_buildPageSettings
(
routeName
,
arguments
);
final
route
=
_getRouteDecoder
<
T
>(
args
);
final
result
=
await
_push
<
T
>(
route
!,
rebuildStack:
rebuildStack
,
);
_route
s
.
removeRoute
(
getPage
);
_route
Tree
.
removeRoute
(
getPage
);
return
result
;
}
...
...
@@ -628,7 +623,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
Future
<
T
?>
_replace
<
T
>(
PageSettings
arguments
,
GetPage
<
T
>
page
)
async
{
final
index
=
_activePages
.
length
>
1
?
_activePages
.
length
-
1
:
0
;
_route
s
.
addRoute
(
page
);
_route
Tree
.
addRoute
(
page
);
final
activePage
=
_getRouteDecoder
(
arguments
);
...
...
@@ -638,7 +633,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
notifyListeners
();
final
result
=
await
activePage
.
route
?.
completer
?.
future
as
Future
<
T
?>?;
_route
s
.
removeRoute
(
page
);
_route
Tree
.
removeRoute
(
page
);
return
result
;
}
...
...
@@ -683,8 +678,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
page
=
uri
.
toString
();
}
final
decoder
=
_routeTree
.
matchRoute
(
registeredRoutes
,
page
,
arguments:
arguments
);
final
decoder
=
_routeTree
.
matchRoute
(
page
,
arguments:
arguments
);
final
route
=
decoder
.
route
;
if
(
route
==
null
)
return
null
;
...
...
@@ -707,7 +701,7 @@ class GetDelegate extends RouterDelegate<RouteDecoder>
completer:
_activePages
.
isEmpty
?
null
:
Completer
(),
arguments:
arguments
,
parameters:
parameters
,
//
key: ValueKey(arguments.name),
key:
ValueKey
(
arguments
.
name
),
);
return
decoder
;
...
...
lib/get_navigation/src/routes/modules.dart
View file @
347dd50
...
...
@@ -13,10 +13,6 @@ class Dependencies {
return
find
<
S
>();
}
Future
<
S
>
putAsync
<
S
>(
AsyncInstanceBuilderCallback
<
S
>
builder
,
{
String
?
tag
,
bool
permanent
=
false
})
async
=>
Get
.
putAsync
<
S
>(
builder
,
tag:
tag
,
permanent:
permanent
);
void
create
<
S
>(
InstanceBuilderCallback
<
S
>
builder
,
{
String
?
tag
,
bool
permanent
=
true
})
=>
Get
.
create
<
S
>(
builder
,
tag:
tag
,
permanent:
permanent
);
...
...
lib/get_navigation/src/routes/parse_route.dart
View file @
347dd50
import
'dart:math'
;
import
'package:flutter/foundation.dart'
;
import
'../../../route_manager.dart'
;
...
...
@@ -18,11 +16,10 @@ class RouteDecoder {
final
args
=
PageSettings
(
uri
);
final
decoder
=
(
Get
.
rootController
.
routerDelegate
as
GetDelegate
)
.
matchRoute
(
location
,
arguments:
args
);
decoder
!.
route
=
decoder
.
route
?.
copy
(
decoder
.
route
=
decoder
.
route
?.
copy
(
completer:
null
,
arguments:
args
,
parameters:
decoder
.
parameter
s
,
parameters:
args
.
param
s
,
);
return
decoder
;
}
...
...
@@ -81,62 +78,96 @@ class RouteDecoder {
}
class
ParseRouteTree
{
RouteDecoder
matchRoute
(
List
<
GetPage
>
routes
,
String
name
,
{
PageSettings
?
arguments
})
{
final
args
=
arguments
??
PageSettings
(
Uri
.
parse
(
name
));
final
treeBranch
=
routes
.
where
((
e
)
=>
RouteParser
.
hasMatch
(
pushedRoute:
name
,
routeName:
e
.
name
,
withChildren:
true
))
.
map
((
e
)
{
final
parameters
=
RouteParser
.
parse
(
pushedRoute:
name
,
routeName:
e
.
name
).
parameters
;
final
routeParams
=
e
.
parameters
;
if
(
routeParams
!=
null
)
{
parameters
.
addAll
(
routeParams
);
}
if
(
args
.
params
.
isNotEmpty
)
{
parameters
.
addAll
(
args
.
params
);
}
args
.
params
.
clear
();
args
.
params
.
addAll
(
parameters
);
return
e
.
copy
(
settings:
args
,
parameters:
parameters
,
ParseRouteTree
({
required
this
.
routes
,
});
final
List
<
GetPage
>
routes
;
RouteDecoder
matchRoute
(
String
name
,
{
PageSettings
?
arguments
})
{
final
uri
=
Uri
.
parse
(
name
);
// /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
((
e
)
=>
MapEntry
(
e
,
_findRoute
(
e
)))
.
where
((
element
)
=>
element
.
value
!=
null
)
///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
);
if
(
treeBranch
.
isNotEmpty
)
{
//route is found, do further parsing to get nested query params
final
lastRoute
=
treeBranch
.
last
;
final
parsedParams
=
_parseParams
(
name
,
lastRoute
.
value
.
path
);
if
(
parsedParams
.
isNotEmpty
)
{
params
.
addAll
(
parsedParams
);
}
//copy parameters to all pages.
final
mappedTreeBranch
=
treeBranch
.
map
(
(
e
)
=>
e
.
value
.
copy
(
parameters:
{
if
(
e
.
value
.
parameters
!=
null
)
...
e
.
value
.
parameters
!,
...
params
,
},
name:
e
.
key
,
),
)
.
toList
();
arguments
?.
params
.
clear
();
arguments
?.
params
.
addAll
(
params
);
return
RouteDecoder
(
mappedTreeBranch
,
arguments
,
);
}).
toList
();
}
arguments
?.
params
.
clear
();
arguments
?.
params
.
addAll
(
params
);
//route not found
return
RouteDecoder
(
treeBranch
,
treeBranch
.
map
((
e
)
=>
e
.
value
).
toList
()
,
arguments
,
);
}
}
extension
FirstWhereOrNullExt
<
T
>
on
List
<
GetPage
<
T
>>
{
void
addRoutes
(
List
<
GetPage
<
T
>>
getPages
)
{
void
addRoutes
<
T
>(
List
<
GetPage
<
T
>>
getPages
)
{
for
(
final
route
in
getPages
)
{
addRoute
(
route
);
}
}
void
removeRoutes
(
List
<
GetPage
<
T
>>
getPages
)
{
void
removeRoutes
<
T
>
(
List
<
GetPage
<
T
>>
getPages
)
{
for
(
final
route
in
getPages
)
{
removeRoute
(
route
);
}
}
void
removeRoute
(
GetPage
<
T
>
route
)
{
remove
(
route
);
void
removeRoute
<
T
>(
GetPage
<
T
>
route
)
{
routes
.
remove
(
route
);
for
(
var
page
in
_flattenPage
(
route
))
{
removeRoute
(
page
);
}
}
void
addRoute
(
GetPage
<
T
>
route
)
{
add
(
route
);
void
addRoute
<
T
>(
GetPage
<
T
>
route
)
{
routes
.
add
(
route
);
// Add Page children.
for
(
var
page
in
_flattenPage
(
route
))
{
...
...
@@ -144,15 +175,14 @@ extension FirstWhereOrNullExt<T> on List<GetPage<T>> {
}
}
List
<
GetPage
<
T
>>
_flattenPage
(
GetPage
<
T
>
route
)
{
final
result
=
<
GetPage
<
T
>>[];
List
<
GetPage
>
_flattenPage
(
GetPage
route
)
{
final
result
=
<
GetPage
>[];
if
(
route
.
children
.
isEmpty
)
{
return
result
;
}
var
parentPathOld
=
route
.
name
;
final
parentPath
=
route
.
name
;
for
(
var
page
in
route
.
children
)
{
final
parentPath2
=
(
parentPathOld
+
page
.
name
).
replaceAll
(
r'//'
,
'/'
);
// Add Parent middlewares to children
final
parentMiddlewares
=
[
if
(
page
.
middlewares
!=
null
)
...
page
.
middlewares
!,
...
...
@@ -160,146 +190,71 @@ extension FirstWhereOrNullExt<T> on List<GetPage<T>> {
];
result
.
add
(
_addChild
(
page
as
GetPage
<
T
>,
parentPath2
,
page
,
parentPath
,
parentMiddlewares
,
),
);
final
children
=
_flattenPage
(
page
);
// for (var child in children) {
// final parentPath = (parentPath2 + page.name).replaceAll(r'//', '/');
// result.add(_addChild(
// child,
// parentPath,
// [
// ...parentMiddlewares,
// if (child.middlewares != null) ...child.middlewares!,
// ],
// ));
// }
for
(
var
child
in
children
)
{
result
.
add
(
_addChild
(
child
,
parentPath
,
[
...
parentMiddlewares
,
if
(
child
.
middlewares
!=
null
)
...
child
.
middlewares
!,
],
));
}
}
return
result
;
}
/// Change the Path for a [GetPage]
GetPage
<
T
>
_addChild
(
GetPage
<
T
>
origin
,
String
parentPath
,
List
<
GetMiddleware
>
middlewares
)
{
GetPage
_addChild
(
GetPage
origin
,
String
parentPath
,
List
<
GetMiddleware
>
middlewares
)
{
return
origin
.
copy
(
middlewares:
middlewares
,
name:
parentPath
,
key:
ValueKey
(
parentPath
),
name:
(
parentPath
+
origin
.
name
).
replaceAll
(
r'//'
,
'/'
),
// key:
);
}
// GetPage<T>? _findRoute(String name) {
// final value = firstWhereOrNull(
// (route) => route.path.regex.hasMatch(name),
// );
// return value;
// }
}
extension
FirstWhereExt
<
T
>
on
List
<
T
>
{
/// The first element satisfying [test], or `null` if there are none.
T
?
firstWhereOrNull
(
bool
Function
(
T
element
)
test
)
{
for
(
var
element
in
this
)
{
if
(
test
(
element
))
return
element
;
}
return
null
;
}
}
class
RouteParser
{
static
RouteParser
parse
({
required
String
pushedRoute
,
required
routeName
})
{
final
data
=
RouteParser
(
pushedRoute:
pushedRoute
,
routeName:
routeName
);
final
minLength
=
min
(
data
.
originalPathSegments
.
length
,
data
.
newPathSegments
.
length
);
for
(
var
i
=
0
;
i
<
minLength
;
i
++)
{
final
originalPathSegment
=
data
.
originalPathSegments
[
i
];
final
newPathSegment
=
Uri
.
parse
(
data
.
newPathSegments
[
i
]);
if
(
originalPathSegment
.
startsWith
(
':'
))
{
final
key
=
originalPathSegment
.
replaceFirst
(
':'
,
''
);
data
.
parameters
[
key
]
=
newPathSegment
.
toString
();
data
.
matchingSegments
.
add
(
newPathSegment
);
continue
;
}
if
(
newPathSegment
.
path
==
originalPathSegment
)
{
data
.
matchingSegments
.
add
(
newPathSegment
);
data
.
parameters
.
addAll
(
data
.
newRouteUri
.
queryParameters
);
continue
;
}
else
{
break
;
}
}
GetPage
?
_findRoute
(
String
name
)
{
final
value
=
routes
.
firstWhereOrNull
(
(
route
)
=>
route
.
path
.
regex
.
hasMatch
(
name
),
);
return
data
;
return
value
;
}
static
bool
hasMatch
({
required
String
pushedRoute
,
required
routeName
,
bool
withChildren
=
false
,
})
{
final
data
=
RouteParser
(
pushedRoute:
pushedRoute
,
routeName:
routeName
);
final
matches
=
<
bool
>[];
final
minLength
=
min
(
data
.
originalPathSegments
.
length
,
data
.
newPathSegments
.
length
);
if
((!
withChildren
&&
data
.
newPathSegments
.
length
>
data
.
originalPathSegments
.
length
)
||
data
.
newPathSegments
.
length
<
data
.
originalPathSegments
.
length
)
{
matches
.
add
(
false
);
Map
<
String
,
String
>
_parseParams
(
String
path
,
PathDecoded
routePath
)
{
final
params
=
<
String
,
String
>{};
var
idx
=
path
.
indexOf
(
'?'
);
if
(
idx
>
-
1
)
{
path
=
path
.
substring
(
0
,
idx
);
final
uri
=
Uri
.
tryParse
(
path
);
if
(
uri
!=
null
)
{
params
.
addAll
(
uri
.
queryParameters
);
}
for
(
var
i
=
0
;
i
<
minLength
;
i
++)
{
final
originalPathSegment
=
data
.
originalPathSegments
[
i
];
final
newPathSegment
=
Uri
.
parse
(
data
.
newPathSegments
[
i
]);
if
(
originalPathSegment
.
startsWith
(
':'
))
{
matches
.
add
(
true
);
continue
;
}
var
paramsMatch
=
routePath
.
regex
.
firstMatch
(
path
);
if
(
newPathSegment
.
path
==
originalPathSegment
)
{
matches
.
add
(
true
);
continue
;
}
else
{
matches
.
add
(
false
);
break
;
for
(
var
i
=
0
;
i
<
routePath
.
keys
.
length
;
i
++)
{
var
param
=
Uri
.
decodeQueryComponent
(
paramsMatch
![
i
+
1
]!);
params
[
routePath
.
keys
[
i
]!]
=
param
;
}
return
params
;
}
}
return
matches
.
every
((
element
)
=>
element
);
extension
FirstWhereOrNullExt
<
T
>
on
List
<
T
>
{
/// The first element satisfying [test], or `null` if there are none.
T
?
firstWhereOrNull
(
bool
Function
(
T
element
)
test
)
{
for
(
var
element
in
this
)
{
if
(
test
(
element
))
return
element
;
}
RouteParser
({
required
String
routeName
,
required
String
pushedRoute
})
:
_cleanRouteName
=
'/'
+
routeName
.
replaceAll
(
RegExp
(
r'^\s+|\s+$'
),
''
)
.
replaceAll
(
RegExp
(
r'^\/+|\/+$'
),
''
),
newRouteUri
=
Uri
.
parse
(
pushedRoute
)
{
originalRouteUri
=
Uri
(
path:
_cleanRouteName
);
return
null
;
}
late
final
Uri
originalRouteUri
;
final
Uri
newRouteUri
;
final
Map
<
String
,
String
>
parameters
=
<
String
,
String
>{};
final
List
<
Uri
>
matchingSegments
=
<
Uri
>[];
final
String
_cleanRouteName
;
List
<
String
>
get
newPathSegments
=>
newRouteUri
.
pathSegments
;
List
<
String
>
get
originalPathSegments
=>
originalRouteUri
.
pathSegments
;
String
get
matchingPath
=>
'/'
+
matchingSegments
.
join
(
'/'
);
@override
String
toString
()
=>
'RouteParser(originalRouteUri:
$originalRouteUri
, newRouteUri:
$newRouteUri
, _cleanRouteName:
$_cleanRouteName
)'
;
}
...
...
lib/get_navigation/src/routes/route_middleware.dart
View file @
347dd50
...
...
@@ -234,9 +234,8 @@ class PageRedirect {
if
(
settings
==
null
&&
route
!=
null
)
{
settings
=
route
;
}
final
match
=
context
.
navigation
.
matchRoute
((
settings
!.
arguments
as
PageSettings
).
name
);
Get
.
parameters
=
match
!.
parameters
;
final
match
=
context
.
navigation
.
matchRoute
(
settings
!.
name
!);
Get
.
parameters
=
match
.
parameters
;
// No Match found
if
(
match
.
route
==
null
)
{
...
...
lib/get_navigation/src/routes/router_outlet.dart
View file @
347dd50
...
...
@@ -147,8 +147,7 @@ class GetRouterOutlet extends RouterOutlet<GetDelegate, RouteDecoder> {
return
ret
;
},
emptyPage:
(
delegate
)
=>
delegate
.
matchRoute
(
initialRoute
)?.
route
??
delegate
.
notFoundRoute
,
delegate
.
matchRoute
(
initialRoute
).
route
??
delegate
.
notFoundRoute
,
key:
Get
.
nestedKey
(
anchorRoute
)?.
navigatorKey
,
delegate:
delegate
,
);
...
...
lib/get_state_manager/src/rx_flutter/rx_notifier.dart
View file @
347dd50
...
...
@@ -68,18 +68,6 @@ mixin StateMixin<T> on ListNotifier {
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
()
Function
()
body
,
...
...
lib/get_state_manager/src/simple/list_notifier.dart
View file @
347dd50
import
'dart:async'
;
import
'dart:collection'
;
import
'package:flutter/foundation.dart'
;
...
...
@@ -24,8 +23,8 @@ class ListNotifierGroup = ListNotifier with ListNotifierGroupMixin;
mixin
ListNotifierSingleMixin
on
Listenable
{
List
<
GetStateUpdate
>?
_updaters
=
<
GetStateUpdate
>[];
int
_version
=
0
;
int
_microtaskVersion
=
0
;
// final int _version = 0;
// final int _microtaskVersion = 0;
@override
Disposer
addListener
(
GetStateUpdate
listener
)
{
...
...
@@ -61,16 +60,18 @@ mixin ListNotifierSingleMixin on Listenable {
}
void
_notifyUpdate
()
{
if
(
_microtaskVersion
==
_version
)
{
_microtaskVersion
++;
scheduleMicrotask
(()
{
_version
++;
_microtaskVersion
=
_version
;
for
(
var
element
in
_updaters
!)
{
// if (_microtaskVersion == _version) {
// _microtaskVersion++;
// scheduleMicrotask(() {
// _version++;
// _microtaskVersion = _version;
final
list
=
_updaters
?.
toList
()
??
[];
for
(
var
element
in
list
)
{
element
();
}
});
}
// });
// }
}
bool
get
isDisposed
=>
_updaters
==
null
;
...
...
lib/get_state_manager/src/simple/simple_builder.dart
View file @
347dd50
...
...
@@ -2,7 +2,6 @@ import 'dart:async';
import
'package:flutter/widgets.dart'
;
import
'../../../get_core/src/typedefs.dart'
;
import
'list_notifier.dart'
;
typedef
ValueBuilderUpdateCallback
<
T
>
=
void
Function
(
T
snapshot
);
...
...
lib/get_utils/get_utils.dart
View file @
347dd50
export
'src/equality/equality.dart'
;
export
'src/extensions/export.dart'
;
export
'src/get_utils/get_utils.dart'
;
export
'src/platform/platform.dart'
;
...
...
lib/get_utils/src/equality/equality.dart
0 → 100644
View file @
347dd50
library
equality
;
import
'dart:collection'
;
mixin
Equality
{
List
get
props
;
@override
bool
operator
==(
dynamic
other
)
{
return
identical
(
this
,
other
)
||
const
DeepCollectionEquality
().
equals
(
props
,
other
.
props
);
}
@override
int
get
hashCode
{
return
runtimeType
.
hashCode
^
const
DeepCollectionEquality
().
hash
(
props
);
}
}
const
int
_hashMask
=
0x7fffffff
;
/// A generic equality relation on objects.
abstract
class
IEquality
<
E
>
{
const
factory
IEquality
()
=
DefaultEquality
<
E
>;
/// Compare two elements for being equal.
///
/// This should be a proper equality relation.
bool
equals
(
E
e1
,
E
e2
);
/// Get a hashcode of an element.
///
/// The hashcode should be compatible with [equals], so that if
/// `equals(a, b)` then `hash(a) == hash(b)`.
int
hash
(
E
e
);
/// Test whether an object is a valid argument to [equals] and [hash].
///
/// Some implementations may be restricted to only work on specific types
/// of objects.
bool
isValidKey
(
Object
?
o
);
}
class
DefaultEquality
<
E
>
implements
IEquality
<
E
>
{
const
DefaultEquality
();
@override
bool
equals
(
Object
?
e1
,
Object
?
e2
)
=>
e1
==
e2
;
@override
int
hash
(
Object
?
e
)
=>
e
.
hashCode
;
@override
bool
isValidKey
(
Object
?
o
)
=>
true
;
}
/// Equality of objects that compares only the identity of the objects.
class
IdentityEquality
<
E
>
implements
IEquality
<
E
>
{
const
IdentityEquality
();
@override
bool
equals
(
E
e1
,
E
e2
)
=>
identical
(
e1
,
e2
);
@override
int
hash
(
E
e
)
=>
identityHashCode
(
e
);
@override
bool
isValidKey
(
Object
?
o
)
=>
true
;
}
class
DeepCollectionEquality
implements
IEquality
{
final
IEquality
_base
=
const
DefaultEquality
<
Never
>();
final
bool
_unordered
=
false
;
const
DeepCollectionEquality
();
@override
bool
equals
(
e1
,
e2
)
{
if
(
e1
is
Set
)
{
return
e2
is
Set
&&
SetEquality
(
this
).
equals
(
e1
,
e2
);
}
if
(
e1
is
Map
)
{
return
e2
is
Map
&&
MapEquality
(
keys:
this
,
values:
this
).
equals
(
e1
,
e2
);
}
if
(
e1
is
List
)
{
return
e2
is
List
&&
ListEquality
(
this
).
equals
(
e1
,
e2
);
}
if
(
e1
is
Iterable
)
{
return
e2
is
Iterable
&&
IterableEquality
(
this
).
equals
(
e1
,
e2
);
}
return
_base
.
equals
(
e1
,
e2
);
}
@override
int
hash
(
Object
?
o
)
{
if
(
o
is
Set
)
return
SetEquality
(
this
).
hash
(
o
);
if
(
o
is
Map
)
return
MapEquality
(
keys:
this
,
values:
this
).
hash
(
o
);
if
(!
_unordered
)
{
if
(
o
is
List
)
return
ListEquality
(
this
).
hash
(
o
);
if
(
o
is
Iterable
)
return
IterableEquality
(
this
).
hash
(
o
);
}
else
if
(
o
is
Iterable
)
{
return
UnorderedIterableEquality
(
this
).
hash
(
o
);
}
return
_base
.
hash
(
o
);
}
@override
bool
isValidKey
(
Object
?
o
)
=>
o
is
Iterable
||
o
is
Map
||
_base
.
isValidKey
(
o
);
}
/// Equality on lists.
///
/// Two lists are equal if they have the same length and their elements
/// at each index are equal.
class
ListEquality
<
E
>
implements
IEquality
<
List
<
E
>>
{
final
IEquality
<
E
>
_elementEquality
;
const
ListEquality
(
[
IEquality
<
E
>
elementEquality
=
const
DefaultEquality
<
Never
>()])
:
_elementEquality
=
elementEquality
;
@override
bool
equals
(
List
<
E
>?
list1
,
List
<
E
>?
list2
)
{
if
(
identical
(
list1
,
list2
))
return
true
;
if
(
list1
==
null
||
list2
==
null
)
return
false
;
var
length
=
list1
.
length
;
if
(
length
!=
list2
.
length
)
return
false
;
for
(
var
i
=
0
;
i
<
length
;
i
++)
{
if
(!
_elementEquality
.
equals
(
list1
[
i
],
list2
[
i
]))
return
false
;
}
return
true
;
}
@override
int
hash
(
List
<
E
>?
list
)
{
if
(
list
==
null
)
return
null
.
hashCode
;
// Jenkins's one-at-a-time hash function.
// This code is almost identical to the one in IterableEquality, except
// that it uses indexing instead of iterating to get the elements.
var
hash
=
0
;
for
(
var
i
=
0
;
i
<
list
.
length
;
i
++)
{
var
c
=
_elementEquality
.
hash
(
list
[
i
]);
hash
=
(
hash
+
c
)
&
_hashMask
;
hash
=
(
hash
+
(
hash
<<
10
))
&
_hashMask
;
hash
^=
(
hash
>>
6
);
}
hash
=
(
hash
+
(
hash
<<
3
))
&
_hashMask
;
hash
^=
(
hash
>>
11
);
hash
=
(
hash
+
(
hash
<<
15
))
&
_hashMask
;
return
hash
;
}
@override
bool
isValidKey
(
Object
?
o
)
=>
o
is
List
<
E
>;
}
/// Equality on maps.
///
/// Two maps are equal if they have the same number of entries, and if the
/// entries of the two maps are pairwise equal on both key and value.
class
MapEquality
<
K
,
V
>
implements
IEquality
<
Map
<
K
,
V
>>
{
final
IEquality
<
K
>
_keyEquality
;
final
IEquality
<
V
>
_valueEquality
;
const
MapEquality
(
{
IEquality
<
K
>
keys
=
const
DefaultEquality
<
Never
>(),
IEquality
<
V
>
values
=
const
DefaultEquality
<
Never
>()})
:
_keyEquality
=
keys
,
_valueEquality
=
values
;
@override
bool
equals
(
Map
<
K
,
V
>?
map1
,
Map
<
K
,
V
>?
map2
)
{
if
(
identical
(
map1
,
map2
))
return
true
;
if
(
map1
==
null
||
map2
==
null
)
return
false
;
var
length
=
map1
.
length
;
if
(
length
!=
map2
.
length
)
return
false
;
Map
<
_MapEntry
,
int
>
equalElementCounts
=
HashMap
();
for
(
var
key
in
map1
.
keys
)
{
var
entry
=
_MapEntry
(
this
,
key
,
map1
[
key
]);
var
count
=
equalElementCounts
[
entry
]
??
0
;
equalElementCounts
[
entry
]
=
count
+
1
;
}
for
(
var
key
in
map2
.
keys
)
{
var
entry
=
_MapEntry
(
this
,
key
,
map2
[
key
]);
var
count
=
equalElementCounts
[
entry
];
if
(
count
==
null
||
count
==
0
)
return
false
;
equalElementCounts
[
entry
]
=
count
-
1
;
}
return
true
;
}
@override
int
hash
(
Map
<
K
,
V
>?
map
)
{
if
(
map
==
null
)
return
null
.
hashCode
;
var
hash
=
0
;
for
(
var
key
in
map
.
keys
)
{
var
keyHash
=
_keyEquality
.
hash
(
key
);
var
valueHash
=
_valueEquality
.
hash
(
map
[
key
]
as
V
);
hash
=
(
hash
+
3
*
keyHash
+
7
*
valueHash
)
&
_hashMask
;
}
hash
=
(
hash
+
(
hash
<<
3
))
&
_hashMask
;
hash
^=
(
hash
>>
11
);
hash
=
(
hash
+
(
hash
<<
15
))
&
_hashMask
;
return
hash
;
}
@override
bool
isValidKey
(
Object
?
o
)
=>
o
is
Map
<
K
,
V
>;
}
class
_MapEntry
{
final
MapEquality
equality
;
final
Object
?
key
;
final
Object
?
value
;
_MapEntry
(
this
.
equality
,
this
.
key
,
this
.
value
);
@override
int
get
hashCode
=>
(
3
*
equality
.
_keyEquality
.
hash
(
key
)
+
7
*
equality
.
_valueEquality
.
hash
(
value
))
&
_hashMask
;
@override
bool
operator
==(
Object
other
)
=>
other
is
_MapEntry
&&
equality
.
_keyEquality
.
equals
(
key
,
other
.
key
)
&&
equality
.
_valueEquality
.
equals
(
value
,
other
.
value
);
}
/// Equality on iterables.
///
/// Two iterables are equal if they have the same elements in the same order.
class
IterableEquality
<
E
>
implements
IEquality
<
Iterable
<
E
>>
{
final
IEquality
<
E
?>
_elementEquality
;
const
IterableEquality
(
[
IEquality
<
E
>
elementEquality
=
const
DefaultEquality
<
Never
>()])
:
_elementEquality
=
elementEquality
;
@override
bool
equals
(
Iterable
<
E
>?
elements1
,
Iterable
<
E
>?
elements2
)
{
if
(
identical
(
elements1
,
elements2
))
return
true
;
if
(
elements1
==
null
||
elements2
==
null
)
return
false
;
var
it1
=
elements1
.
iterator
;
var
it2
=
elements2
.
iterator
;
while
(
true
)
{
var
hasNext
=
it1
.
moveNext
();
if
(
hasNext
!=
it2
.
moveNext
())
return
false
;
if
(!
hasNext
)
return
true
;
if
(!
_elementEquality
.
equals
(
it1
.
current
,
it2
.
current
))
return
false
;
}
}
@override
int
hash
(
Iterable
<
E
>?
elements
)
{
if
(
elements
==
null
)
return
null
.
hashCode
;
// Jenkins's one-at-a-time hash function.
var
hash
=
0
;
for
(
var
element
in
elements
)
{
var
c
=
_elementEquality
.
hash
(
element
);
hash
=
(
hash
+
c
)
&
_hashMask
;
hash
=
(
hash
+
(
hash
<<
10
))
&
_hashMask
;
hash
^=
(
hash
>>
6
);
}
hash
=
(
hash
+
(
hash
<<
3
))
&
_hashMask
;
hash
^=
(
hash
>>
11
);
hash
=
(
hash
+
(
hash
<<
15
))
&
_hashMask
;
return
hash
;
}
@override
bool
isValidKey
(
Object
?
o
)
=>
o
is
Iterable
<
E
>;
}
/// Equality of sets.
///
/// Two sets are considered equal if they have the same number of elements,
/// and the elements of one set can be paired with the elements
/// of the other set, so that each pair are equal.
class
SetEquality
<
E
>
extends
_UnorderedEquality
<
E
,
Set
<
E
>>
{
const
SetEquality
(
[
IEquality
<
E
>
elementEquality
=
const
DefaultEquality
<
Never
>()])
:
super
(
elementEquality
);
@override
bool
isValidKey
(
Object
?
o
)
=>
o
is
Set
<
E
>;
}
abstract
class
_UnorderedEquality
<
E
,
T
extends
Iterable
<
E
>>
implements
IEquality
<
T
>
{
final
IEquality
<
E
>
_elementEquality
;
const
_UnorderedEquality
(
this
.
_elementEquality
);
@override
bool
equals
(
T
?
elements1
,
T
?
elements2
)
{
if
(
identical
(
elements1
,
elements2
))
return
true
;
if
(
elements1
==
null
||
elements2
==
null
)
return
false
;
var
counts
=
HashMap
<
E
,
int
>(
equals:
_elementEquality
.
equals
,
hashCode:
_elementEquality
.
hash
,
isValidKey:
_elementEquality
.
isValidKey
);
var
length
=
0
;
for
(
var
e
in
elements1
)
{
var
count
=
counts
[
e
]
??
0
;
counts
[
e
]
=
count
+
1
;
length
++;
}
for
(
var
e
in
elements2
)
{
var
count
=
counts
[
e
];
if
(
count
==
null
||
count
==
0
)
return
false
;
counts
[
e
]
=
count
-
1
;
length
--;
}
return
length
==
0
;
}
@override
int
hash
(
T
?
elements
)
{
if
(
elements
==
null
)
return
null
.
hashCode
;
var
hash
=
0
;
for
(
E
element
in
elements
)
{
var
c
=
_elementEquality
.
hash
(
element
);
hash
=
(
hash
+
c
)
&
_hashMask
;
}
hash
=
(
hash
+
(
hash
<<
3
))
&
_hashMask
;
hash
^=
(
hash
>>
11
);
hash
=
(
hash
+
(
hash
<<
15
))
&
_hashMask
;
return
hash
;
}
}
/// Equality of the elements of two iterables without considering order.
///
/// Two iterables are considered equal if they have the same number of elements,
/// and the elements of one set can be paired with the elements
/// of the other iterable, so that each pair are equal.
class
UnorderedIterableEquality
<
E
>
extends
_UnorderedEquality
<
E
,
Iterable
<
E
>>
{
const
UnorderedIterableEquality
(
[
IEquality
<
E
>
elementEquality
=
const
DefaultEquality
<
Never
>()])
:
super
(
elementEquality
);
@override
bool
isValidKey
(
Object
?
o
)
=>
o
is
Iterable
<
E
>;
}
...
...
test/instance/get_instance_test.dart
View file @
347dd50
...
...
@@ -29,12 +29,7 @@ class Api implements Service {
}
void
main
(
)
{
test
(
'Get.putAsync test'
,
()
async
{
await
Get
.
putAsync
<
String
>(
Mock
.
test
);
expect
(
'test'
,
Get
.
find
<
String
>());
Get
.
reset
();
});
TestWidgetsFlutterBinding
.
ensureInitialized
();
test
(
'Get.put test'
,
()
async
{
final
instance
=
Get
.
put
<
Controller
>(
Controller
());
expect
(
instance
,
Get
.
find
<
Controller
>());
...
...
test/navigation/parse_route_test.dart
View file @
347dd50
...
...
@@ -4,7 +4,7 @@ import 'package:get/get.dart';
void
main
(
)
{
test
(
'Parse Page with children'
,
()
{
//
final testParams = {'hi': 'value'};
final
testParams
=
{
'hi'
:
'value'
};
final
pageTree
=
GetPage
(
name:
'/city'
,
page:
()
=>
Container
(),
...
...
@@ -40,7 +40,7 @@ void main() {
name:
'/pen'
,
transition:
Transition
.
cupertino
,
page:
()
=>
Container
(),
//
parameters: testParams,
parameters:
testParams
,
),
GetPage
(
name:
'/paper'
,
...
...
@@ -58,63 +58,20 @@ void main() {
),
],
);
final
routes
=
<
GetPage
>[];
final
tree
=
ParseRouteTree
();
routes
.
addRoute
(
pageTree
);
final
tree
=
ParseRouteTree
(
routes:
<
GetPage
>[]);
tree
.
addRoute
(
pageTree
);
// tree.addRoute(pageTree);
final
searchRoute
=
'/city/work/office/pen'
;
final
match
=
tree
.
matchRoute
(
routes
,
searchRoute
);
final
match
=
tree
.
matchRoute
(
searchRoute
);
expect
(
match
,
isNotNull
);
expect
(
match
.
route
!.
name
,
searchRoute
);
final
testRouteParam
=
match
.
parameters
;
print
(
testRouteParam
);
// for (final tParam in testParams.entries) {
// expect(testRouteParam[tParam.key], tParam.value);
// }
});
test
(
'Parse '
,
()
{
final
testParams
=
{
'hi'
:
'value'
};
final
pageTree
=
GetPage
(
name:
'/city'
,
parameters:
testParams
,
page:
()
=>
Container
(),
);
final
routes
=
<
GetPage
>[];
final
tree
=
ParseRouteTree
();
routes
.
addRoute
(
pageTree
);
// tree.addRoute(pageTree);
final
searchRoute
=
'/city?abc=1234'
;
final
hasMatch
=
RouteParser
.
hasMatch
(
pushedRoute:
searchRoute
,
routeName:
pageTree
.
name
);
expect
(
hasMatch
,
true
);
final
parsed
=
RouteParser
.
parse
(
pushedRoute:
searchRoute
,
routeName:
pageTree
.
name
);
final
match
=
tree
.
matchRoute
(
routes
,
searchRoute
);
expect
(
match
,
isNotNull
);
expect
(
parsed
.
newRouteUri
.
toString
(),
searchRoute
);
final
testRouteParam
=
match
.
route
?.
parameters
;
final
testRouteParam
=
match
.
route
!.
parameters
!;
for
(
final
tParam
in
testParams
.
entries
)
{
expect
(
testRouteParam
!
[
tParam
.
key
],
tParam
.
value
);
expect
(
testRouteParam
[
tParam
.
key
],
tParam
.
value
);
}
final
hasMatch2
=
RouteParser
.
hasMatch
(
pushedRoute:
'/home/123/ana'
,
routeName:
'/home/:id/:name'
);
print
(
hasMatch2
);
expect
(
hasMatch2
,
true
);
final
parsed2
=
RouteParser
.
parse
(
pushedRoute:
'/home/123/ana/profile'
,
routeName:
'/home/:id/:name/profile'
);
print
(
parsed2
.
parameters
);
});
test
(
'Parse Page without children'
,
()
{
...
...
@@ -157,14 +114,14 @@ void main() {
transition:
Transition
.
rightToLeft
),
];
final
tree
=
ParseRouteTree
();
final
tree
=
ParseRouteTree
(
routes:
pageTree
);
// for (var p in pageTree) {
// tree.addRoute(p);
// }
final
searchRoute
=
'/city/work/office/pen'
;
final
match
=
tree
.
matchRoute
(
pageTree
,
searchRoute
);
final
match
=
tree
.
matchRoute
(
searchRoute
);
expect
(
match
,
isNotNull
);
expect
(
match
.
route
!.
name
,
searchRoute
);
});
...
...
@@ -182,8 +139,6 @@ void main() {
],
));
print
(
Get
.
parameters
);
expect
(
Get
.
parameters
[
'name'
],
'juan'
);
Get
.
toNamed
(
'/second/1234'
);
...
...
test/state_manager/get_obx_test.dart
View file @
347dd50
...
...
@@ -3,8 +3,8 @@ import 'package:flutter_test/flutter_test.dart';
import
'package:get/get.dart'
;
void
main
(
)
{
final
controller
=
Get
.
put
(
Controller
());
testWidgets
(
"GetxController smoke test"
,
(
tester
)
async
{
final
controller
=
Get
.
put
(
Controller
());
await
tester
.
pumpWidget
(
MaterialApp
(
home:
Column
(
...
...
Please
register
or
login
to post a comment