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
2020-08-29 20:42:57 -0300
Browse Files
Options
Browse Files
Download
Plain Diff
Committed by
GitHub
2020-08-29 20:42:57 -0300
Commit
f7fb338482d3f915618bf6c83b05316dca231cc3
f7fb3384
2 parents
b8722049
b3364bc2
Merge pull request #523 from roipeker/master
General cleanup, more docs.
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
305 additions
and
96 deletions
lib/src/instance/extension_instance.dart
lib/src/instance/get_instance.dart
lib/src/navigation/extension_navigation.dart
lib/src/navigation/root/parse_route.dart
lib/src/state_manager/rx/rx_impl.dart
lib/src/state_manager/rx/rx_interface.dart
lib/src/state_manager/rx/utils/debouncer.dart
lib/src/instance/extension_instance.dart
View file @
f7fb338
...
...
@@ -3,11 +3,33 @@ import 'package:get/src/core/get_interface.dart';
import
'get_instance.dart'
;
extension
Inst
on
GetInterface
{
/// Creates a new Instance<S> lazily from the [<S>builder()] callback.
///
/// The first time you call [Get.find()], the [builder()] callback will create
/// the Instance and persisted as a Singleton (like you would use [Get.put()]).
///
/// Using [GetConfig.smartManagement] as [SmartManagement.keepFactory] has the same outcome
/// as using [fenix:true] :
/// The internal register of [builder()] will remain in memory to recreate the Instance
/// if the Instance has been removed with [Get.delete()].
/// Therefore, future calls to [Get.find()] will return the same Instance.
///
/// If you need to make use of GetxController's life-cycle ([onInit(), onStart(), onClose()])
/// [fenix] is a great choice to mix with [GetBuilder()] and [GetX()] widgets, and/or [GetMaterialApp] Navigation.
///
/// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead of [Bindings()] for each [GetPage].
/// And the memory management will be similar.
///
/// Subsequent calls to [Get.lazyPut()] with the same parameters (<[S]> and optionally [tag]
/// will **not** override the original).
void
lazyPut
<
S
>(
InstanceBuilderCallback
<
S
>
builder
,
{
String
tag
,
bool
fenix
=
false
})
{
return
GetInstance
().
lazyPut
<
S
>(
builder
,
tag:
tag
,
fenix:
fenix
);
GetInstance
().
lazyPut
<
S
>(
builder
,
tag:
tag
,
fenix:
fenix
);
}
/// 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
=>
GetInstance
().
putAsync
<
S
>(
builder
,
tag:
tag
,
permanent:
permanent
);
...
...
@@ -22,26 +44,26 @@ extension Inst on GetInterface {
/// Repl a = find();
/// Repl b = find();
/// print(a==b); (false)```
///
void
create
<
S
>(
InstanceBuilderCallback
<
S
>
builder
,
{
String
name
,
bool
permanent
=
true
})
=>
GetInstance
().
create
<
S
>(
builder
,
name:
name
,
permanent:
permanent
);
/// Finds a instance of the required Class<[S]> (or [tag])
/// In the case of using Get.[create], it will create an instance
/// each time you call [find]
///
/// Finds a Instance of the required Class <[S]>(or [tag])
/// In the case of using [Get.create()], it will generate an Instance
/// each time you call [Get.find()].
S
find
<
S
>({
String
tag
})
=>
GetInstance
().
find
<
S
>(
tag:
tag
);
/// Injects a
Instance [S] in [GetInstance]
.
/// Injects a
n [Instance<S>] in memory
.
///
/// No need to define the generic type <[S]> as it's inferred from the [dependency]
/// parameter.
///
/// - [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 [GetConfig.smartManagement]
/// rules
///
/// the [tag] does **not** conflict with the same tags used by other [dependencies] Types.
/// - [permanent] keeps the Instance in memory and persist it, not following [GetConfig.smartManagement]
/// rules. Although, can be removed by [GetInstance.reset()] and [Get.delete()]
/// - [builder] If defined, the [dependency] must be returned from here
S
put
<
S
>(
S
dependency
,
{
String
tag
,
bool
permanent
=
false
,
...
...
@@ -49,14 +71,25 @@ extension Inst on GetInterface {
GetInstance
()
.
put
<
S
>(
dependency
,
tag:
tag
,
permanent:
permanent
,
builder:
builder
);
/// Clears all registered instances (and/or tags).
/// Even the persistent ones.
///
/// - [clearFactory] clears the callbacks registered by [Get.lazyPut()]
/// - [clearRouteBindings] clears Instances associated with Routes when using
/// [GetMaterialApp].
bool
reset
({
bool
clearFactory
=
true
,
bool
clearRouteBindings
=
true
})
=>
GetInstance
().
reset
(
clearFactory:
clearFactory
,
clearRouteBindings:
clearRouteBindings
);
/// Delete class instance on [S] and clean memory
Future
<
bool
>
delete
<
S
>({
String
tag
,
String
key
})
async
=>
GetInstance
().
delete
<
S
>(
tag:
tag
,
key:
key
);
/// Deletes the Instance<[S]>, cleaning the memory and closes any open
/// controllers ([DisposableInterface]).
///
/// - [tag] Optional "tag" used to register the Instance
Future
<
bool
>
delete
<
S
>({
String
tag
})
async
=>
GetInstance
().
delete
<
S
>(
tag:
tag
);
/// Check if a Class Instance<[S]> (or [tag]) is registered in memory.
/// - [tag] optional, if you use a [tag] to register the Instance.
bool
isRegistered
<
S
>({
String
tag
})
=>
GetInstance
().
isRegistered
<
S
>(
tag:
tag
);
bool
isPrepared
<
S
>({
String
tag
})
=>
GetInstance
().
isPrepared
<
S
>(
tag:
tag
);
...
...
lib/src/instance/get_instance.dart
View file @
f7fb338
...
...
@@ -12,27 +12,53 @@ class GetConfig {
class
GetInstance
{
factory
GetInstance
()
=>
_getInstance
??=
GetInstance
.
_
();
const
GetInstance
.
_
();
static
GetInstance
_getInstance
;
/// Holds references to every registered Instance when using
/// Get.[put]
static
Map
<
String
,
_FcBuilder
>
_singl
=
{};
/// [Get.put()]
static
Map
<
String
,
_InstanceBuilderFactory
>
_singl
=
{};
/// Holds a reference to every registered callback when using
///
Get.[lazyPut
]
///
[Get.lazyPut()
]
static
Map
<
String
,
_Lazy
>
_factory
=
{};
/// Holds a reference to [GetConfig.currentRoute] when the Instance was
/// created to manage the memory.
static
Map
<
String
,
String
>
_routesKey
=
{};
static
GetQueue
_queue
=
GetQueue
();
/// Creates a new Instance<S> lazily from the [<S>builder()] callback.
///
/// The first time you call [Get.find()], the [builder()] callback will create
/// the Instance and persisted as a Singleton (like you would use [Get.put()]).
///
/// Using [GetConfig.smartManagement] as [SmartManagement.keepFactory] has the same outcome
/// as using [fenix:true] :
/// The internal register of [builder()] will remain in memory to recreate the Instance
/// if the Instance has been removed with [Get.delete()].
/// Therefore, future calls to [Get.find()] will return the same Instance.
///
/// If you need to make use of GetxController's life-cycle ([onInit(), onStart(), onClose()])
/// [fenix] is a great choice to mix with [GetBuilder()] and [GetX()] widgets, and/or [GetMaterialApp] Navigation.
///
/// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead of [Bindings()] for each [GetPage].
/// And the memory management will be similar.
///
/// Subsequent calls to [Get.lazyPut()] with the same parameters (<[S]> and optionally [tag]
/// will **not** override the original).
void
lazyPut
<
S
>(
InstanceBuilderCallback
<
S
>
builder
,
{
String
tag
,
bool
fenix
=
false
})
{
String
key
=
_getKey
(
S
,
tag
);
_factory
.
putIfAbsent
(
key
,
()
=>
_Lazy
(
builder
,
fenix
));
}
/// 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
);
...
...
@@ -89,7 +115,9 @@ class GetInstance {
assert
(
builder
!=
null
);
final
key
=
_getKey
(
S
,
name
);
_singl
.
putIfAbsent
(
key
,
()
=>
_FcBuilder
<
S
>(
isSingleton
,
builder
,
permanent
,
false
));
key
,
()
=>
_InstanceBuilderFactory
<
S
>(
isSingleton
,
builder
,
permanent
,
false
));
}
/// Clears from memory registered Instances associated with [routeName] when
...
...
@@ -181,8 +209,8 @@ class GetInstance {
S
find
<
S
>({
String
tag
})
{
String
key
=
_getKey
(
S
,
tag
);
if
(
isRegistered
<
S
>(
tag:
tag
))
{
_FcBuilder
builder
=
_singl
[
key
];
if
(
builder
==
null
)
{
if
(
_singl
[
key
]
==
null
)
{
if
(
tag
==
null
)
{
throw
'Class "
$S
" is not register'
;
}
else
{
...
...
@@ -190,14 +218,12 @@ class GetInstance {
}
}
_initDependencies
<
S
>(
name:
tag
);
return
_singl
[
key
].
getDependency
()
as
S
;
}
else
{
if
(!
_factory
.
containsKey
(
key
))
throw
'"
$S
" not found. You need to call "Get.put
<
$S
>(
$S
())"'
;
throw
'"
$S
" not found. You need to call "Get.put
(
$S
())" or "Get.lazyPut(()=>
$S
())"'
;
// TODO: This message is not clear
GetConfig
.
log
(
'"
$S
" instance was created at that time'
);
GetConfig
.
log
(
'Lazy instance "
$S
" created'
);
S
_value
=
put
<
S
>(
_factory
[
key
].
builder
()
as
S
);
...
...
@@ -212,6 +238,8 @@ class GetInstance {
}
}
/// Generates the key based on [type] (and optionally a [name])
/// to register an Instance Builder in the hashmap.
String
_getKey
(
Type
type
,
String
name
)
{
return
name
==
null
?
type
.
toString
()
:
type
.
toString
()
+
name
;
}
...
...
@@ -237,6 +265,20 @@ class GetInstance {
/// Delete registered Class Instance [S] (or [tag]) and, closes any open
/// controllers [DisposableInterface], cleans up the memory
///
/// /// Deletes the Instance<[S]>, cleaning the memory.
// ///
// /// - [tag] Optional "tag" used to register the Instance
// /// - [key] For internal usage, is the processed key used to register
// /// the Instance. **don't use** it unless you know what you are doing.
/// Deletes the Instance<[S]>, cleaning the memory and closes any open
/// controllers ([DisposableInterface]).
///
/// - [tag] Optional "tag" used to register the Instance
/// - [key] For internal usage, is the processed key used to register
/// the Instance. **don't use** it unless you know what you are doing.
/// - [force] Will delete an Instance even if marked as [permanent].
Future
<
bool
>
delete
<
S
>({
String
tag
,
String
key
,
bool
force
=
false
})
async
{
final
newKey
=
key
??
_getKey
(
S
,
tag
);
...
...
@@ -246,11 +288,12 @@ class GetInstance {
return
false
;
}
_FcBuilder
builder
=
_singl
[
newKey
];
final
builder
=
_singl
[
newKey
];
if
(
builder
.
permanent
&&
!
force
)
{
GetConfig
.
log
(
'"
$newKey
" has been marked as permanent, SmartManagement is not authorized to delete it.'
,
isError:
true
);
'"
$newKey
" has been marked as permanent, SmartManagement is not authorized to delete it.'
,
isError:
true
,
);
return
false
;
}
final
i
=
builder
.
dependency
;
...
...
@@ -274,10 +317,13 @@ class GetInstance {
});
}
/// Check if a Class instance [S] (or [tag]) is registered.
/// Check if a Class Instance<[S]> (or [tag]) is registered in memory.
/// - [tag] optional, if you use a [tag] to register the Instance.
bool
isRegistered
<
S
>({
String
tag
})
=>
_singl
.
containsKey
(
_getKey
(
S
,
tag
));
/// Check if Class instance [S] (or [tag]) is prepared to be used.
/// Checks if a lazy factory callback that returns an Instance<[S]>
/// is registered.
/// - [tag] optional, if you use a [tag] to register the Instance.
bool
isPrepared
<
S
>({
String
tag
})
=>
_factory
.
containsKey
(
_getKey
(
S
,
tag
));
}
...
...
@@ -286,7 +332,7 @@ typedef InstanceBuilderCallback<S> = S Function();
typedef
AsyncInstanceBuilderCallback
<
S
>
=
Future
<
S
>
Function
();
/// Internal class to register instances with Get.[put]<[S]>().
class
_
FcBuilder
<
S
>
{
class
_
InstanceBuilderFactory
<
S
>
{
/// Marks the Builder as a single instance.
/// For reusing [dependency] instead of [builderFunc]
bool
isSingleton
;
...
...
@@ -304,7 +350,8 @@ class _FcBuilder<S> {
bool
isInit
=
false
;
_FcBuilder
(
this
.
isSingleton
,
this
.
builderFunc
,
this
.
permanent
,
this
.
isInit
);
_InstanceBuilderFactory
(
this
.
isSingleton
,
this
.
builderFunc
,
this
.
permanent
,
this
.
isInit
);
/// Gets the actual instance by it's [builderFunc] or the persisted instance.
S
getDependency
()
{
...
...
lib/src/navigation/extension_navigation.dart
View file @
f7fb338
import
'package:flutter/material.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:get/src/core/get_interface.dart'
;
import
'package:get/instance_manager.dart'
;
import
'package:get/route_manager.dart'
;
import
'package:get/src/core/get_interface.dart'
;
import
'package:get/src/core/log.dart'
;
import
'dialog/dialog_route.dart'
;
import
'root/parse_route.dart'
;
import
'routes/bindings_interface.dart'
;
...
...
@@ -13,6 +14,8 @@ import 'routes/bindings_interface.dart';
NavigatorState
get
navigator
=>
Get
.
key
.
currentState
;
extension
GetNavigation
on
GetInterface
{
/// **Navigation.push()** shortcut.<br><br>
///
/// Pushes a new [page] to the stack
///
/// It has the advantage of not needing context,
...
...
@@ -69,7 +72,9 @@ extension GetNavigation on GetInterface {
);
}
/// Pushes a new named [page] to the stack
/// **Navigation.pushNamed()** shortcut.<br><br>
///
/// Pushes a new named [page] to the stack.
///
/// It has the advantage of not needing context, so you can call
/// from your business logic.
...
...
@@ -95,6 +100,8 @@ extension GetNavigation on GetInterface {
return
global
(
id
).
currentState
.
pushNamed
(
page
,
arguments:
arguments
);
}
/// **Navigation.pushReplacementNamed()** shortcut.<br><br>
///
/// Pop the current named [page] in the stack and push a new one in its place
///
/// It has the advantage of not needing context, so you can call
...
...
@@ -123,6 +130,8 @@ extension GetNavigation on GetInterface {
.
pushReplacementNamed
(
page
,
arguments:
arguments
);
}
/// **Navigation.popUntil()** shortcut.<br><br>
///
/// Calls pop several times in the stack until [predicate] returns true
///
/// [id] is for when you are using nested navigation,
...
...
@@ -139,6 +148,8 @@ extension GetNavigation on GetInterface {
return
global
(
id
).
currentState
.
popUntil
(
predicate
);
}
/// **Navigation.pushAndRemoveUntil()** shortcut.<br><br>
///
/// Push the given [page], and then pop several pages in the stack until
/// [predicate] returns true
///
...
...
@@ -160,6 +171,8 @@ extension GetNavigation on GetInterface {
return
global
(
id
).
currentState
.
pushAndRemoveUntil
(
page
,
predicate
);
}
/// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
///
/// Push the given named [page], and then pop several pages in the stack
/// until [predicate] returns true
///
...
...
@@ -185,6 +198,8 @@ extension GetNavigation on GetInterface {
.
pushNamedAndRemoveUntil
(
page
,
predicate
,
arguments:
arguments
);
}
/// **Navigation.popAndPushNamed()** shortcut.<br><br>
///
/// Pop the current named page and pushes a new [page] to the stack in its place
///
/// You can send any type of value to the other route in the [arguments].
...
...
@@ -200,6 +215,8 @@ extension GetNavigation on GetInterface {
.
popAndPushNamed
(
page
,
arguments:
arguments
,
result:
result
);
}
/// **Navigation.removeRoute()** shortcut.<br><br>
///
/// Remove a specific [route] from the stack
///
/// [id] is for when you are using nested navigation,
...
...
@@ -208,6 +225,8 @@ extension GetNavigation on GetInterface {
return
global
(
id
).
currentState
.
removeRoute
(
route
);
}
/// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
///
/// Push a named [page] and pop several pages in the stack
/// until [predicate] returns true. [predicate] is optional
///
...
...
@@ -234,14 +253,16 @@ extension GetNavigation on GetInterface {
arguments:
arguments
);
}
/// Returns true if a
snackbar, dialog or bottomsheet is currently showing in the screen
/// Returns true if a
Snackbar, Dialog or BottomSheet is currently showing
bool
get
isOverlaysOpen
=>
(
isSnackbarOpen
||
isDialogOpen
||
isBottomSheetOpen
);
///
returns true if there is no snackbar, dialog or bottoms
heet open
///
Returns true if there is no Snackbar, Dialog or BottomS
heet open
bool
get
isOverlaysClosed
=>
(!
isSnackbarOpen
&&
!
isDialogOpen
&&
!
isBottomSheetOpen
);
/// **Navigation.popUntil()** shortcut.<br><br>
///
/// Pop the current page, snackbar, dialog or bottomsheet in the stack
///
/// if your set [closeOverlays] to true, Get.back() will close the currently open
...
...
@@ -272,6 +293,8 @@ extension GetNavigation on GetInterface {
}
}
/// **Navigation.popUntil()** (with predicate) shortcut .<br><br>
///
/// Close as many routes as defined by [times]
///
/// [id] is for when you are using nested navigation,
...
...
@@ -287,6 +310,8 @@ extension GetNavigation on GetInterface {
return
back
;
}
/// **Navigation.pushReplacement()** shortcut .<br><br>
///
/// Pop the current page and pushes a new [page] to the stack
///
/// It has the advantage of not needing context,
...
...
@@ -337,6 +362,8 @@ extension GetNavigation on GetInterface {
transitionDuration:
duration
??
defaultDurationTransition
));
}
/// **Navigation.pushAndRemoveUntil()** shortcut .<br><br>
///
/// Push a [page] and pop several pages in the stack
/// until [predicate] returns true. [predicate] is optional
///
...
...
@@ -470,6 +497,7 @@ extension GetNavigation on GetInterface {
));
}
/// Custom UI Dialog.
Future
<
T
>
defaultDialog
<
T
>({
String
title
=
"Alert"
,
Widget
content
,
...
...
@@ -884,7 +912,7 @@ extension GetNavigation on GetInterface {
return
key
;
}
if
(!
keys
.
containsKey
(
k
))
{
throw
'
route id
not found'
;
throw
'
Route id (
$k
)
not found'
;
}
return
keys
[
k
];
}
...
...
@@ -892,7 +920,7 @@ extension GetNavigation on GetInterface {
RouteSettings
get
routeSettings
=>
settings
;
void
setSettings
(
RouteSettings
settings
)
{
settings
=
settings
;
this
.
settings
=
settings
;
}
/// give current arguments
...
...
lib/src/navigation/root/parse_route.dart
View file @
f7fb338
import
'package:flutter/widgets.dart'
;
import
'package:get/src/navigation/routes/get_route.dart'
;
class
GetPageMatch
{
GetPageMatch
(
this
.
route
);
GetPage
route
;
Map
<
String
,
String
>
parameters
=
<
String
,
String
>{};
}
class
ParseRouteTree
{
final
List
<
ParseRouteTreeNode
>
_nodes
=
<
ParseRouteTreeNode
>[];
final
List
<
_ParseRouteTreeNode
>
_nodes
=
<
_
ParseRouteTreeNode
>[];
// bool _hasDefaultRoute = false;
...
...
@@ -20,7 +13,7 @@ class ParseRouteTree {
// if (_hasDefaultRoute) {
// throw ("Default route was already defined");
// }
var
node
=
ParseRouteTreeNode
(
path
,
ParseRouteTreeNodeType
.
component
);
var
node
=
_ParseRouteTreeNode
(
path
,
_
ParseRouteTreeNodeType
.
component
);
node
.
routes
=
[
route
];
_nodes
.
add
(
node
);
// _hasDefaultRoute = true;
...
...
@@ -30,13 +23,13 @@ class ParseRouteTree {
path
=
path
.
substring
(
1
);
}
List
<
String
>
pathComponents
=
path
.
split
(
'/'
);
ParseRouteTreeNode
parent
;
_
ParseRouteTreeNode
parent
;
for
(
int
i
=
0
;
i
<
pathComponents
.
length
;
i
++)
{
String
component
=
pathComponents
[
i
];
ParseRouteTreeNode
node
=
_nodeForComponent
(
component
,
parent
);
_
ParseRouteTreeNode
node
=
_nodeForComponent
(
component
,
parent
);
if
(
node
==
null
)
{
ParseRouteTreeNodeType
type
=
_typeForComponent
(
component
);
node
=
ParseRouteTreeNode
(
component
,
type
);
_ParseRouteTreeNodeType
type
=
_typeForComponent
(
component
);
node
=
_ParseRouteTreeNode
(
component
,
type
);
node
.
parent
=
parent
;
if
(
parent
==
null
)
{
_nodes
.
add
(
node
);
...
...
@@ -55,7 +48,7 @@ class ParseRouteTree {
}
}
GetPageMatch
matchRoute
(
String
path
)
{
_
GetPageMatch
matchRoute
(
String
path
)
{
String
usePath
=
path
;
if
(
usePath
.
startsWith
(
"/"
))
{
usePath
=
path
.
substring
(
1
);
...
...
@@ -68,14 +61,14 @@ class ParseRouteTree {
if
(
path
==
Navigator
.
defaultRouteName
)
{
components
=
[
"/"
];
}
Map
<
ParseRouteTreeNode
,
ParseRouteTreeNodeMatch
>
nodeMatches
=
<
ParseRouteTreeNode
,
ParseRouteTreeNodeMatch
>{};
List
<
ParseRouteTreeNode
>
nodesToCheck
=
_nodes
;
Map
<
_ParseRouteTreeNode
,
_ParseRouteTreeNodeMatch
>
nodeMatches
=
<
_ParseRouteTreeNode
,
_ParseRouteTreeNodeMatch
>{};
List
<
_ParseRouteTreeNode
>
nodesToCheck
=
_nodes
;
for
(
String
checkComponent
in
components
)
{
Map
<
ParseRouteTreeNode
,
ParseRouteTreeNodeMatch
>
currentMatches
=
<
ParseRouteTreeNode
,
ParseRouteTreeNodeMatch
>{};
List
<
ParseRouteTreeNode
>
nextNodes
=
<
ParseRouteTreeNode
>[];
for
(
ParseRouteTreeNode
node
in
nodesToCheck
)
{
Map
<
_ParseRouteTreeNode
,
_ParseRouteTreeNodeMatch
>
currentMatches
=
<
_ParseRouteTreeNode
,
_ParseRouteTreeNodeMatch
>{};
List
<
_ParseRouteTreeNode
>
nextNodes
=
<
_ParseRouteTreeNode
>[];
for
(
_ParseRouteTreeNode
node
in
nodesToCheck
)
{
String
pathPart
=
checkComponent
;
Map
<
String
,
String
>
queryMap
=
{};
...
...
@@ -104,9 +97,9 @@ class ParseRouteTree {
bool
isMatch
=
(
node
.
part
==
pathPart
||
node
.
isParameter
());
if
(
isMatch
)
{
ParseRouteTreeNodeMatch
parentMatch
=
nodeMatches
[
node
.
parent
];
ParseRouteTreeNodeMatch
match
=
ParseRouteTreeNodeMatch
.
fromMatch
(
parentMatch
,
node
);
_ParseRouteTreeNodeMatch
parentMatch
=
nodeMatches
[
node
.
parent
];
_ParseRouteTreeNodeMatch
match
=
_ParseRouteTreeNodeMatch
.
fromMatch
(
parentMatch
,
node
);
// TODO: find a way to clean this implementation.
match
.
parameters
.
addAll
(
uri
.
queryParameters
);
...
...
@@ -131,16 +124,16 @@ class ParseRouteTree {
return
null
;
}
}
List
<
ParseRouteTreeNodeMatch
>
matches
=
nodeMatches
.
values
.
toList
();
List
<
_
ParseRouteTreeNodeMatch
>
matches
=
nodeMatches
.
values
.
toList
();
if
(
matches
.
length
>
0
)
{
ParseRouteTreeNodeMatch
match
=
matches
.
first
;
ParseRouteTreeNode
nodeToUse
=
match
.
node
;
_ParseRouteTreeNodeMatch
match
=
matches
.
first
;
_ParseRouteTreeNode
nodeToUse
=
match
.
node
;
if
(
nodeToUse
!=
null
&&
nodeToUse
.
routes
!=
null
&&
nodeToUse
.
routes
.
length
>
0
)
{
List
<
GetPage
>
routes
=
nodeToUse
.
routes
;
GetPageMatch
routeMatch
=
GetPageMatch
(
routes
[
0
]);
_GetPageMatch
routeMatch
=
_
GetPageMatch
(
routes
[
0
]);
routeMatch
.
parameters
=
match
.
parameters
;
...
...
@@ -150,13 +143,13 @@ class ParseRouteTree {
return
null
;
}
ParseRouteTreeNode
_nodeForComponent
(
String
component
,
ParseRouteTreeNode
parent
)
{
List
<
ParseRouteTreeNode
>
nodes
=
_nodes
;
_ParseRouteTreeNode
_nodeForComponent
(
String
component
,
_ParseRouteTreeNode
parent
)
{
List
<
_ParseRouteTreeNode
>
nodes
=
_nodes
;
if
(
parent
!=
null
)
{
nodes
=
parent
.
nodes
;
}
for
(
ParseRouteTreeNode
node
in
nodes
)
{
for
(
_
ParseRouteTreeNode
node
in
nodes
)
{
if
(
node
.
part
==
component
)
{
return
node
;
}
...
...
@@ -164,10 +157,10 @@ class ParseRouteTree {
return
null
;
}
ParseRouteTreeNodeType
_typeForComponent
(
String
component
)
{
ParseRouteTreeNodeType
type
=
ParseRouteTreeNodeType
.
component
;
_ParseRouteTreeNodeType
_typeForComponent
(
String
component
)
{
_ParseRouteTreeNodeType
type
=
_ParseRouteTreeNodeType
.
component
;
if
(
_isParameterComponent
(
component
))
{
type
=
ParseRouteTreeNodeType
.
parameter
;
type
=
_
ParseRouteTreeNodeType
.
parameter
;
}
return
type
;
}
...
...
@@ -190,35 +183,43 @@ class ParseRouteTree {
}
}
class
ParseRouteTreeNodeMatch
{
ParseRouteTreeNodeMatch
(
this
.
node
);
class
_ParseRouteTreeNodeMatch
{
_ParseRouteTreeNodeMatch
(
this
.
node
);
ParseRouteTreeNodeMatch
.
fromMatch
(
ParseRouteTreeNodeMatch
match
,
this
.
node
)
{
_ParseRouteTreeNodeMatch
.
fromMatch
(
_ParseRouteTreeNodeMatch
match
,
this
.
node
)
{
parameters
=
<
String
,
String
>{};
if
(
match
!=
null
)
{
parameters
.
addAll
(
match
.
parameters
);
}
}
ParseRouteTreeNode
node
;
_
ParseRouteTreeNode
node
;
Map
<
String
,
String
>
parameters
=
<
String
,
String
>{};
}
class
ParseRouteTreeNode
{
ParseRouteTreeNode
(
this
.
part
,
this
.
type
);
class
_ParseRouteTreeNode
{
_ParseRouteTreeNode
(
this
.
part
,
this
.
type
);
String
part
;
ParseRouteTreeNodeType
type
;
_
ParseRouteTreeNodeType
type
;
List
<
GetPage
>
routes
=
<
GetPage
>[];
List
<
ParseRouteTreeNode
>
nodes
=
<
ParseRouteTreeNode
>[];
ParseRouteTreeNode
parent
;
List
<
_ParseRouteTreeNode
>
nodes
=
<
_ParseRouteTreeNode
>[];
_ParseRouteTreeNode
parent
;
bool
isParameter
()
{
return
type
==
ParseRouteTreeNodeType
.
parameter
;
return
type
==
_
ParseRouteTreeNodeType
.
parameter
;
}
}
enum
ParseRouteTreeNodeType
{
class
_GetPageMatch
{
_GetPageMatch
(
this
.
route
);
GetPage
route
;
Map
<
String
,
String
>
parameters
=
<
String
,
String
>{};
}
enum
_ParseRouteTreeNodeType
{
component
,
parameter
,
}
...
...
lib/src/state_manager/rx/rx_impl.dart
View file @
f7fb338
...
...
@@ -38,11 +38,69 @@ class _RxImpl<T> implements RxInterface<T> {
bool
get
canUpdate
=>
_subscriptions
.
isNotEmpty
;
/// Makes this Rx looks like a function so you can update a new
/// value using [rx(someOtherValue)]. Practical to assign the Rx directly
/// to some Widget that has a signature ::onChange( value )
///
/// Example:
/// ```
/// final myText = 'GetX rocks!'.obs;
///
/// // in your Constructor, just to check it works :P
/// ever( myText, print ) ;
///
/// // in your build(BuildContext) {
/// TextField(
// onChanged: myText,
// ),
///```
T
call
([
T
v
])
{
if
(
v
!=
null
)
this
.
value
=
v
;
return
this
.
value
;
}
/// Makes a direct update of [value] adding it to the Stream
/// useful when you make use of Rx for custom Types to referesh your UI.
///
/// Sample:
/// ```
/// class Person {
/// String name, last;
/// int age;
/// Person({this.name, this.last, this.age});
/// @override
/// String toString() => '$name $last, $age years old';
/// }
///
/// final person = Person(name: 'John', last: 'Doe', age: 18).obs;
/// person.value.name = 'Roi';
/// person.refresh();
/// print( person );
/// ```
void
refresh
()
{
subject
.
add
(
value
);
}
/// Uses a callback to update [value] internally, similar to [refresh], but provides
/// the current value as the argument.
/// Makes sense for custom Rx types (like Models).
///
/// Sample:
/// ```
/// class Person {
/// String name, last;
/// int age;
/// Person({this.name, this.last, this.age});
/// @override
/// String toString() => '$name $last, $age years old';
/// }
///
/// final person = Person(name: 'John', last: 'Doe', age: 18).obs;
/// person.update((person) {
/// person.name = 'Roi';
/// });
/// print( person );
/// ```
void
update
(
void
fn
(
T
value
))
{
fn
(
value
);
subject
.
add
(
value
);
...
...
lib/src/state_manager/rx/rx_interface.dart
View file @
f7fb338
...
...
@@ -3,20 +3,22 @@ import 'dart:async';
import
'package:flutter/scheduler.dart'
;
import
'package:get/src/state_manager/rx/rx_callbacks.dart'
;
/// This class is the foundation for all reactive (Rx) classes that makes Get
/// so powerful.
/// This interface is the contract that [_RxImpl]<[T]> uses in all it's
/// subclass.
abstract
class
RxInterface
<
T
>
{
RxInterface
([
T
initial
]);
/// add listener to stream
StreamController
<
T
>
subject
;
/// Adds a listener to stream
void
addListener
(
Stream
<
T
>
rxGetx
);
bool
get
canUpdate
;
/// close stream
void
close
()
{
subject
?.
close
();
}
StreamController
<
T
>
subject
;
/// Closes the stream
void
close
()
=>
subject
?.
close
();
/// Calls [callback] with current value, when the value changes.
StreamSubscription
<
T
>
listen
(
ValueCallback
<
T
>
callback
);
...
...
@@ -60,14 +62,40 @@ abstract class DisposableInterface {
SchedulerBinding
.
instance
?.
addPostFrameCallback
((
_
)
=>
onReady
());
}
/// Called Called immediately after the widget is allocated in memory.
/// Called immediately after the widget is allocated in memory.
/// You might use this initialize something for the controller.
void
onInit
()
async
{}
/// Called after rendering the screen. It is the perfect place to enter navigation events,
/// be it snackbar, dialogs, or a new route.
/// Called 1 frame after onInit(). It is the perfect place to enter navigation events,
/// like snackbar, dialogs, or a new route, or async request.
void
onReady
()
async
{}
/// Called before the onDelete method. onClose is used to close events
/// before the controller is destroyed, such as closing streams, for example.
onClose
()
async
{}
/// Called before [onDelete] method. [onClose] might be used to dispose resources
/// used by the controller. Like closing events, or streams before the controller is destroyed.
/// Or dispose objects that can potentially create some memory leaks,
/// like TextEditingControllers, AnimationControllers.
/// Might be useful as well to persist some data on disk.
void
onClose
()
async
{}
}
/// Used like [SingleTickerProviderMixin] but only with Get Controllers.
/// Simplifies AnimationController creation inside GetxController.
///
/// Example:
///```
///class SplashController extends GetxController with SingleGetTickerProviderMixin {
/// AnimationController _ac;
///
/// @override
/// void onInit() {
/// final dur = const Duration(seconds: 2);
/// _ac = AnimationController.unbounded(duration: dur, vsync: this);
/// _ac.repeat();
/// _ac.addListener(() => print("Animation Controller value: ${_ac.value}"));
/// }
/// ...
/// ```
mixin
SingleGetTickerProviderMixin
on
DisposableInterface
implements
TickerProvider
{
Ticker
createTicker
(
TickerCallback
onTick
)
=>
Ticker
(
onTick
);
}
...
...
lib/src/state_manager/rx/utils/debouncer.dart
View file @
f7fb338
import
'dart:async'
;
/// This "function" class is the implementation of [debouncer()] Worker.
/// It calls the function passed after specified [delay] parameter.
/// Example:
/// ```
/// final delayed = Debouncer( delay: Duration( seconds: 1 )) ;
/// print( 'the next function will be called after 1 sec' );
/// delayed( () => print( 'called after 1 sec' ));
/// ```
class
Debouncer
{
final
Duration
delay
;
Timer
_timer
;
Debouncer
({
this
.
delay
});
call
(
void
Function
()
action
)
{
void
call
(
void
Function
()
action
)
{
_timer
?.
cancel
();
_timer
=
Timer
(
delay
,
action
);
}
/// Notifies if the delayed call is active.
bool
get
isRunning
=>
_timer
?.
isActive
??
false
;
/// Cancel the current delayed call.
void
cancel
()
=>
_timer
?.
cancel
();
}
...
...
Please
register
or
login
to post a comment