Jonny Borges
Committed by GitHub

Merge pull request #523 from roipeker/master

General cleanup, more docs.
@@ -3,11 +3,33 @@ import 'package:get/src/core/get_interface.dart'; @@ -3,11 +3,33 @@ import 'package:get/src/core/get_interface.dart';
3 import 'get_instance.dart'; 3 import 'get_instance.dart';
4 4
5 extension Inst on GetInterface { 5 extension Inst on GetInterface {
  6 + /// Creates a new Instance<S> lazily from the [<S>builder()] callback.
  7 + ///
  8 + /// The first time you call [Get.find()], the [builder()] callback will create
  9 + /// the Instance and persisted as a Singleton (like you would use [Get.put()]).
  10 + ///
  11 + /// Using [GetConfig.smartManagement] as [SmartManagement.keepFactory] has the same outcome
  12 + /// as using [fenix:true] :
  13 + /// The internal register of [builder()] will remain in memory to recreate the Instance
  14 + /// if the Instance has been removed with [Get.delete()].
  15 + /// Therefore, future calls to [Get.find()] will return the same Instance.
  16 + ///
  17 + /// If you need to make use of GetxController's life-cycle ([onInit(), onStart(), onClose()])
  18 + /// [fenix] is a great choice to mix with [GetBuilder()] and [GetX()] widgets, and/or [GetMaterialApp] Navigation.
  19 + ///
  20 + /// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead of [Bindings()] for each [GetPage].
  21 + /// And the memory management will be similar.
  22 + ///
  23 + /// Subsequent calls to [Get.lazyPut()] with the same parameters (<[S]> and optionally [tag]
  24 + /// will **not** override the original).
6 void lazyPut<S>(InstanceBuilderCallback<S> builder, 25 void lazyPut<S>(InstanceBuilderCallback<S> builder,
7 {String tag, bool fenix = false}) { 26 {String tag, bool fenix = false}) {
8 - return GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix); 27 + GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix);
9 } 28 }
10 29
  30 + /// async version of [Get.put()].
  31 + /// Awaits for the resolution of the Future from [builder()] parameter and
  32 + /// stores the Instance returned.
11 Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder, 33 Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
12 {String tag, bool permanent = false}) async => 34 {String tag, bool permanent = false}) async =>
13 GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent); 35 GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
@@ -22,26 +44,26 @@ extension Inst on GetInterface { @@ -22,26 +44,26 @@ extension Inst on GetInterface {
22 /// Repl a = find(); 44 /// Repl a = find();
23 /// Repl b = find(); 45 /// Repl b = find();
24 /// print(a==b); (false)``` 46 /// print(a==b); (false)```
25 - ///  
26 void create<S>(InstanceBuilderCallback<S> builder, 47 void create<S>(InstanceBuilderCallback<S> builder,
27 {String name, bool permanent = true}) => 48 {String name, bool permanent = true}) =>
28 GetInstance().create<S>(builder, name: name, permanent: permanent); 49 GetInstance().create<S>(builder, name: name, permanent: permanent);
29 50
30 - /// Finds a instance of the required Class<[S]> (or [tag])  
31 - /// In the case of using Get.[create], it will create an instance  
32 - /// each time you call [find]  
33 - /// 51 + /// Finds a Instance of the required Class <[S]>(or [tag])
  52 + /// In the case of using [Get.create()], it will generate an Instance
  53 + /// each time you call [Get.find()].
34 S find<S>({String tag}) => GetInstance().find<S>(tag: tag); 54 S find<S>({String tag}) => GetInstance().find<S>(tag: tag);
35 55
36 - /// Injects a Instance [S] in [GetInstance]. 56 + /// Injects an [Instance<S>] in memory.
37 /// 57 ///
38 /// No need to define the generic type <[S]> as it's inferred from the [dependency] 58 /// No need to define the generic type <[S]> as it's inferred from the [dependency]
  59 + /// parameter.
39 /// 60 ///
40 /// - [dependency] The Instance to be injected. 61 /// - [dependency] The Instance to be injected.
41 /// - [tag] optionally, use a [tag] as an "id" to create multiple records of the same Type<[S]> 62 /// - [tag] optionally, use a [tag] as an "id" to create multiple records of the same Type<[S]>
42 - /// - [permanent] keeps the Instance in memory, not following [GetConfig.smartManagement]  
43 - /// rules  
44 - /// 63 + /// the [tag] does **not** conflict with the same tags used by other [dependencies] Types.
  64 + /// - [permanent] keeps the Instance in memory and persist it, not following [GetConfig.smartManagement]
  65 + /// rules. Although, can be removed by [GetInstance.reset()] and [Get.delete()]
  66 + /// - [builder] If defined, the [dependency] must be returned from here
45 S put<S>(S dependency, 67 S put<S>(S dependency,
46 {String tag, 68 {String tag,
47 bool permanent = false, 69 bool permanent = false,
@@ -49,14 +71,25 @@ extension Inst on GetInterface { @@ -49,14 +71,25 @@ extension Inst on GetInterface {
49 GetInstance() 71 GetInstance()
50 .put<S>(dependency, tag: tag, permanent: permanent, builder: builder); 72 .put<S>(dependency, tag: tag, permanent: permanent, builder: builder);
51 73
  74 + /// Clears all registered instances (and/or tags).
  75 + /// Even the persistent ones.
  76 + ///
  77 + /// - [clearFactory] clears the callbacks registered by [Get.lazyPut()]
  78 + /// - [clearRouteBindings] clears Instances associated with Routes when using
  79 + /// [GetMaterialApp].
52 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) => 80 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) =>
53 GetInstance().reset( 81 GetInstance().reset(
54 clearFactory: clearFactory, clearRouteBindings: clearRouteBindings); 82 clearFactory: clearFactory, clearRouteBindings: clearRouteBindings);
55 83
56 - /// Delete class instance on [S] and clean memory  
57 - Future<bool> delete<S>({String tag, String key}) async =>  
58 - GetInstance().delete<S>(tag: tag, key: key); 84 + /// Deletes the Instance<[S]>, cleaning the memory and closes any open
  85 + /// controllers ([DisposableInterface]).
  86 + ///
  87 + /// - [tag] Optional "tag" used to register the Instance
  88 + Future<bool> delete<S>({String tag}) async =>
  89 + GetInstance().delete<S>(tag: tag);
59 90
  91 + /// Check if a Class Instance<[S]> (or [tag]) is registered in memory.
  92 + /// - [tag] optional, if you use a [tag] to register the Instance.
60 bool isRegistered<S>({String tag}) => GetInstance().isRegistered<S>(tag: tag); 93 bool isRegistered<S>({String tag}) => GetInstance().isRegistered<S>(tag: tag);
61 94
62 bool isPrepared<S>({String tag}) => GetInstance().isPrepared<S>(tag: tag); 95 bool isPrepared<S>({String tag}) => GetInstance().isPrepared<S>(tag: tag);
@@ -12,27 +12,53 @@ class GetConfig { @@ -12,27 +12,53 @@ class GetConfig {
12 12
13 class GetInstance { 13 class GetInstance {
14 factory GetInstance() => _getInstance ??= GetInstance._(); 14 factory GetInstance() => _getInstance ??= GetInstance._();
  15 +
15 const GetInstance._(); 16 const GetInstance._();
  17 +
16 static GetInstance _getInstance; 18 static GetInstance _getInstance;
17 19
18 /// Holds references to every registered Instance when using 20 /// Holds references to every registered Instance when using
19 - /// Get.[put]  
20 - static Map<String, _FcBuilder> _singl = {}; 21 + /// [Get.put()]
  22 + static Map<String, _InstanceBuilderFactory> _singl = {};
21 23
22 /// Holds a reference to every registered callback when using 24 /// Holds a reference to every registered callback when using
23 - /// Get.[lazyPut] 25 + /// [Get.lazyPut()]
24 static Map<String, _Lazy> _factory = {}; 26 static Map<String, _Lazy> _factory = {};
25 27
  28 + /// Holds a reference to [GetConfig.currentRoute] when the Instance was
  29 + /// created to manage the memory.
26 static Map<String, String> _routesKey = {}; 30 static Map<String, String> _routesKey = {};
27 31
28 static GetQueue _queue = GetQueue(); 32 static GetQueue _queue = GetQueue();
29 33
  34 + /// Creates a new Instance<S> lazily from the [<S>builder()] callback.
  35 + ///
  36 + /// The first time you call [Get.find()], the [builder()] callback will create
  37 + /// the Instance and persisted as a Singleton (like you would use [Get.put()]).
  38 + ///
  39 + /// Using [GetConfig.smartManagement] as [SmartManagement.keepFactory] has the same outcome
  40 + /// as using [fenix:true] :
  41 + /// The internal register of [builder()] will remain in memory to recreate the Instance
  42 + /// if the Instance has been removed with [Get.delete()].
  43 + /// Therefore, future calls to [Get.find()] will return the same Instance.
  44 + ///
  45 + /// If you need to make use of GetxController's life-cycle ([onInit(), onStart(), onClose()])
  46 + /// [fenix] is a great choice to mix with [GetBuilder()] and [GetX()] widgets, and/or [GetMaterialApp] Navigation.
  47 + ///
  48 + /// You could use [Get.lazyPut(fenix:true)] in your app's [main()] instead of [Bindings()] for each [GetPage].
  49 + /// And the memory management will be similar.
  50 + ///
  51 + /// Subsequent calls to [Get.lazyPut()] with the same parameters (<[S]> and optionally [tag]
  52 + /// will **not** override the original).
30 void lazyPut<S>(InstanceBuilderCallback<S> builder, 53 void lazyPut<S>(InstanceBuilderCallback<S> builder,
31 {String tag, bool fenix = false}) { 54 {String tag, bool fenix = false}) {
32 String key = _getKey(S, tag); 55 String key = _getKey(S, tag);
33 _factory.putIfAbsent(key, () => _Lazy(builder, fenix)); 56 _factory.putIfAbsent(key, () => _Lazy(builder, fenix));
34 } 57 }
35 58
  59 + /// async version of [Get.put()].
  60 + /// Awaits for the resolution of the Future from [builder()] parameter and
  61 + /// stores the Instance returned.
36 Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder, 62 Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder,
37 {String tag, bool permanent = false}) async { 63 {String tag, bool permanent = false}) async {
38 return put<S>(await builder(), tag: tag, permanent: permanent); 64 return put<S>(await builder(), tag: tag, permanent: permanent);
@@ -89,7 +115,9 @@ class GetInstance { @@ -89,7 +115,9 @@ class GetInstance {
89 assert(builder != null); 115 assert(builder != null);
90 final key = _getKey(S, name); 116 final key = _getKey(S, name);
91 _singl.putIfAbsent( 117 _singl.putIfAbsent(
92 - key, () => _FcBuilder<S>(isSingleton, builder, permanent, false)); 118 + key,
  119 + () =>
  120 + _InstanceBuilderFactory<S>(isSingleton, builder, permanent, false));
93 } 121 }
94 122
95 /// Clears from memory registered Instances associated with [routeName] when 123 /// Clears from memory registered Instances associated with [routeName] when
@@ -181,8 +209,8 @@ class GetInstance { @@ -181,8 +209,8 @@ class GetInstance {
181 S find<S>({String tag}) { 209 S find<S>({String tag}) {
182 String key = _getKey(S, tag); 210 String key = _getKey(S, tag);
183 if (isRegistered<S>(tag: tag)) { 211 if (isRegistered<S>(tag: tag)) {
184 - _FcBuilder builder = _singl[key];  
185 - if (builder == null) { 212 +
  213 + if (_singl[key] == null) {
186 if (tag == null) { 214 if (tag == null) {
187 throw 'Class "$S" is not register'; 215 throw 'Class "$S" is not register';
188 } else { 216 } else {
@@ -190,14 +218,12 @@ class GetInstance { @@ -190,14 +218,12 @@ class GetInstance {
190 } 218 }
191 } 219 }
192 _initDependencies<S>(name: tag); 220 _initDependencies<S>(name: tag);
193 -  
194 return _singl[key].getDependency() as S; 221 return _singl[key].getDependency() as S;
195 } else { 222 } else {
196 if (!_factory.containsKey(key)) 223 if (!_factory.containsKey(key))
197 - throw '"$S" not found. You need to call "Get.put<$S>($S())"'; 224 + throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
198 225
199 - // TODO: This message is not clear  
200 - GetConfig.log('"$S" instance was created at that time'); 226 + GetConfig.log('Lazy instance "$S" created');
201 227
202 S _value = put<S>(_factory[key].builder() as S); 228 S _value = put<S>(_factory[key].builder() as S);
203 229
@@ -212,6 +238,8 @@ class GetInstance { @@ -212,6 +238,8 @@ class GetInstance {
212 } 238 }
213 } 239 }
214 240
  241 + /// Generates the key based on [type] (and optionally a [name])
  242 + /// to register an Instance Builder in the hashmap.
215 String _getKey(Type type, String name) { 243 String _getKey(Type type, String name) {
216 return name == null ? type.toString() : type.toString() + name; 244 return name == null ? type.toString() : type.toString() + name;
217 } 245 }
@@ -237,6 +265,20 @@ class GetInstance { @@ -237,6 +265,20 @@ class GetInstance {
237 265
238 /// Delete registered Class Instance [S] (or [tag]) and, closes any open 266 /// Delete registered Class Instance [S] (or [tag]) and, closes any open
239 /// controllers [DisposableInterface], cleans up the memory 267 /// controllers [DisposableInterface], cleans up the memory
  268 + ///
  269 + /// /// Deletes the Instance<[S]>, cleaning the memory.
  270 + // ///
  271 + // /// - [tag] Optional "tag" used to register the Instance
  272 + // /// - [key] For internal usage, is the processed key used to register
  273 + // /// the Instance. **don't use** it unless you know what you are doing.
  274 +
  275 + /// Deletes the Instance<[S]>, cleaning the memory and closes any open
  276 + /// controllers ([DisposableInterface]).
  277 + ///
  278 + /// - [tag] Optional "tag" used to register the Instance
  279 + /// - [key] For internal usage, is the processed key used to register
  280 + /// the Instance. **don't use** it unless you know what you are doing.
  281 + /// - [force] Will delete an Instance even if marked as [permanent].
240 Future<bool> delete<S>({String tag, String key, bool force = false}) async { 282 Future<bool> delete<S>({String tag, String key, bool force = false}) async {
241 final newKey = key ?? _getKey(S, tag); 283 final newKey = key ?? _getKey(S, tag);
242 284
@@ -246,11 +288,12 @@ class GetInstance { @@ -246,11 +288,12 @@ class GetInstance {
246 return false; 288 return false;
247 } 289 }
248 290
249 - _FcBuilder builder = _singl[newKey]; 291 + final builder = _singl[newKey];
250 if (builder.permanent && !force) { 292 if (builder.permanent && !force) {
251 GetConfig.log( 293 GetConfig.log(
252 - '"$newKey" has been marked as permanent, SmartManagement is not authorized to delete it.',  
253 - isError: true); 294 + '"$newKey" has been marked as permanent, SmartManagement is not authorized to delete it.',
  295 + isError: true,
  296 + );
254 return false; 297 return false;
255 } 298 }
256 final i = builder.dependency; 299 final i = builder.dependency;
@@ -274,10 +317,13 @@ class GetInstance { @@ -274,10 +317,13 @@ class GetInstance {
274 }); 317 });
275 } 318 }
276 319
277 - /// Check if a Class instance [S] (or [tag]) is registered. 320 + /// Check if a Class Instance<[S]> (or [tag]) is registered in memory.
  321 + /// - [tag] optional, if you use a [tag] to register the Instance.
278 bool isRegistered<S>({String tag}) => _singl.containsKey(_getKey(S, tag)); 322 bool isRegistered<S>({String tag}) => _singl.containsKey(_getKey(S, tag));
279 323
280 - /// Check if Class instance [S] (or [tag]) is prepared to be used. 324 + /// Checks if a lazy factory callback that returns an Instance<[S]>
  325 + /// is registered.
  326 + /// - [tag] optional, if you use a [tag] to register the Instance.
281 bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag)); 327 bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag));
282 } 328 }
283 329
@@ -286,7 +332,7 @@ typedef InstanceBuilderCallback<S> = S Function(); @@ -286,7 +332,7 @@ typedef InstanceBuilderCallback<S> = S Function();
286 typedef AsyncInstanceBuilderCallback<S> = Future<S> Function(); 332 typedef AsyncInstanceBuilderCallback<S> = Future<S> Function();
287 333
288 /// Internal class to register instances with Get.[put]<[S]>(). 334 /// Internal class to register instances with Get.[put]<[S]>().
289 -class _FcBuilder<S> { 335 +class _InstanceBuilderFactory<S> {
290 /// Marks the Builder as a single instance. 336 /// Marks the Builder as a single instance.
291 /// For reusing [dependency] instead of [builderFunc] 337 /// For reusing [dependency] instead of [builderFunc]
292 bool isSingleton; 338 bool isSingleton;
@@ -304,7 +350,8 @@ class _FcBuilder<S> { @@ -304,7 +350,8 @@ class _FcBuilder<S> {
304 350
305 bool isInit = false; 351 bool isInit = false;
306 352
307 - _FcBuilder(this.isSingleton, this.builderFunc, this.permanent, this.isInit); 353 + _InstanceBuilderFactory(
  354 + this.isSingleton, this.builderFunc, this.permanent, this.isInit);
308 355
309 /// Gets the actual instance by it's [builderFunc] or the persisted instance. 356 /// Gets the actual instance by it's [builderFunc] or the persisted instance.
310 S getDependency() { 357 S getDependency() {
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter/scheduler.dart'; 2 import 'package:flutter/scheduler.dart';
3 -import 'package:get/src/core/get_interface.dart';  
4 import 'package:get/instance_manager.dart'; 3 import 'package:get/instance_manager.dart';
5 import 'package:get/route_manager.dart'; 4 import 'package:get/route_manager.dart';
  5 +import 'package:get/src/core/get_interface.dart';
6 import 'package:get/src/core/log.dart'; 6 import 'package:get/src/core/log.dart';
  7 +
7 import 'dialog/dialog_route.dart'; 8 import 'dialog/dialog_route.dart';
8 import 'root/parse_route.dart'; 9 import 'root/parse_route.dart';
9 import 'routes/bindings_interface.dart'; 10 import 'routes/bindings_interface.dart';
@@ -13,6 +14,8 @@ import 'routes/bindings_interface.dart'; @@ -13,6 +14,8 @@ import 'routes/bindings_interface.dart';
13 NavigatorState get navigator => Get.key.currentState; 14 NavigatorState get navigator => Get.key.currentState;
14 15
15 extension GetNavigation on GetInterface { 16 extension GetNavigation on GetInterface {
  17 + /// **Navigation.push()** shortcut.<br><br>
  18 + ///
16 /// Pushes a new [page] to the stack 19 /// Pushes a new [page] to the stack
17 /// 20 ///
18 /// It has the advantage of not needing context, 21 /// It has the advantage of not needing context,
@@ -69,7 +72,9 @@ extension GetNavigation on GetInterface { @@ -69,7 +72,9 @@ extension GetNavigation on GetInterface {
69 ); 72 );
70 } 73 }
71 74
72 - /// Pushes a new named [page] to the stack 75 + /// **Navigation.pushNamed()** shortcut.<br><br>
  76 + ///
  77 + /// Pushes a new named [page] to the stack.
73 /// 78 ///
74 /// It has the advantage of not needing context, so you can call 79 /// It has the advantage of not needing context, so you can call
75 /// from your business logic. 80 /// from your business logic.
@@ -95,6 +100,8 @@ extension GetNavigation on GetInterface { @@ -95,6 +100,8 @@ extension GetNavigation on GetInterface {
95 return global(id).currentState.pushNamed(page, arguments: arguments); 100 return global(id).currentState.pushNamed(page, arguments: arguments);
96 } 101 }
97 102
  103 + /// **Navigation.pushReplacementNamed()** shortcut.<br><br>
  104 + ///
98 /// Pop the current named [page] in the stack and push a new one in its place 105 /// Pop the current named [page] in the stack and push a new one in its place
99 /// 106 ///
100 /// It has the advantage of not needing context, so you can call 107 /// It has the advantage of not needing context, so you can call
@@ -123,6 +130,8 @@ extension GetNavigation on GetInterface { @@ -123,6 +130,8 @@ extension GetNavigation on GetInterface {
123 .pushReplacementNamed(page, arguments: arguments); 130 .pushReplacementNamed(page, arguments: arguments);
124 } 131 }
125 132
  133 + /// **Navigation.popUntil()** shortcut.<br><br>
  134 + ///
126 /// Calls pop several times in the stack until [predicate] returns true 135 /// Calls pop several times in the stack until [predicate] returns true
127 /// 136 ///
128 /// [id] is for when you are using nested navigation, 137 /// [id] is for when you are using nested navigation,
@@ -139,6 +148,8 @@ extension GetNavigation on GetInterface { @@ -139,6 +148,8 @@ extension GetNavigation on GetInterface {
139 return global(id).currentState.popUntil(predicate); 148 return global(id).currentState.popUntil(predicate);
140 } 149 }
141 150
  151 + /// **Navigation.pushAndRemoveUntil()** shortcut.<br><br>
  152 + ///
142 /// Push the given [page], and then pop several pages in the stack until 153 /// Push the given [page], and then pop several pages in the stack until
143 /// [predicate] returns true 154 /// [predicate] returns true
144 /// 155 ///
@@ -160,6 +171,8 @@ extension GetNavigation on GetInterface { @@ -160,6 +171,8 @@ extension GetNavigation on GetInterface {
160 return global(id).currentState.pushAndRemoveUntil(page, predicate); 171 return global(id).currentState.pushAndRemoveUntil(page, predicate);
161 } 172 }
162 173
  174 + /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
  175 + ///
163 /// Push the given named [page], and then pop several pages in the stack 176 /// Push the given named [page], and then pop several pages in the stack
164 /// until [predicate] returns true 177 /// until [predicate] returns true
165 /// 178 ///
@@ -185,6 +198,8 @@ extension GetNavigation on GetInterface { @@ -185,6 +198,8 @@ extension GetNavigation on GetInterface {
185 .pushNamedAndRemoveUntil(page, predicate, arguments: arguments); 198 .pushNamedAndRemoveUntil(page, predicate, arguments: arguments);
186 } 199 }
187 200
  201 + /// **Navigation.popAndPushNamed()** shortcut.<br><br>
  202 + ///
188 /// Pop the current named page and pushes a new [page] to the stack in its place 203 /// Pop the current named page and pushes a new [page] to the stack in its place
189 /// 204 ///
190 /// You can send any type of value to the other route in the [arguments]. 205 /// You can send any type of value to the other route in the [arguments].
@@ -200,6 +215,8 @@ extension GetNavigation on GetInterface { @@ -200,6 +215,8 @@ extension GetNavigation on GetInterface {
200 .popAndPushNamed(page, arguments: arguments, result: result); 215 .popAndPushNamed(page, arguments: arguments, result: result);
201 } 216 }
202 217
  218 + /// **Navigation.removeRoute()** shortcut.<br><br>
  219 + ///
203 /// Remove a specific [route] from the stack 220 /// Remove a specific [route] from the stack
204 /// 221 ///
205 /// [id] is for when you are using nested navigation, 222 /// [id] is for when you are using nested navigation,
@@ -208,6 +225,8 @@ extension GetNavigation on GetInterface { @@ -208,6 +225,8 @@ extension GetNavigation on GetInterface {
208 return global(id).currentState.removeRoute(route); 225 return global(id).currentState.removeRoute(route);
209 } 226 }
210 227
  228 + /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
  229 + ///
211 /// Push a named [page] and pop several pages in the stack 230 /// Push a named [page] and pop several pages in the stack
212 /// until [predicate] returns true. [predicate] is optional 231 /// until [predicate] returns true. [predicate] is optional
213 /// 232 ///
@@ -234,14 +253,16 @@ extension GetNavigation on GetInterface { @@ -234,14 +253,16 @@ extension GetNavigation on GetInterface {
234 arguments: arguments); 253 arguments: arguments);
235 } 254 }
236 255
237 - /// Returns true if a snackbar, dialog or bottomsheet is currently showing in the screen 256 + /// Returns true if a Snackbar, Dialog or BottomSheet is currently showing
238 bool get isOverlaysOpen => 257 bool get isOverlaysOpen =>
239 (isSnackbarOpen || isDialogOpen || isBottomSheetOpen); 258 (isSnackbarOpen || isDialogOpen || isBottomSheetOpen);
240 259
241 - /// returns true if there is no snackbar, dialog or bottomsheet open 260 + /// Returns true if there is no Snackbar, Dialog or BottomSheet open
242 bool get isOverlaysClosed => 261 bool get isOverlaysClosed =>
243 (!isSnackbarOpen && !isDialogOpen && !isBottomSheetOpen); 262 (!isSnackbarOpen && !isDialogOpen && !isBottomSheetOpen);
244 263
  264 + /// **Navigation.popUntil()** shortcut.<br><br>
  265 + ///
245 /// Pop the current page, snackbar, dialog or bottomsheet in the stack 266 /// Pop the current page, snackbar, dialog or bottomsheet in the stack
246 /// 267 ///
247 /// if your set [closeOverlays] to true, Get.back() will close the currently open 268 /// if your set [closeOverlays] to true, Get.back() will close the currently open
@@ -272,6 +293,8 @@ extension GetNavigation on GetInterface { @@ -272,6 +293,8 @@ extension GetNavigation on GetInterface {
272 } 293 }
273 } 294 }
274 295
  296 + /// **Navigation.popUntil()** (with predicate) shortcut .<br><br>
  297 + ///
275 /// Close as many routes as defined by [times] 298 /// Close as many routes as defined by [times]
276 /// 299 ///
277 /// [id] is for when you are using nested navigation, 300 /// [id] is for when you are using nested navigation,
@@ -287,6 +310,8 @@ extension GetNavigation on GetInterface { @@ -287,6 +310,8 @@ extension GetNavigation on GetInterface {
287 return back; 310 return back;
288 } 311 }
289 312
  313 + /// **Navigation.pushReplacement()** shortcut .<br><br>
  314 + ///
290 /// Pop the current page and pushes a new [page] to the stack 315 /// Pop the current page and pushes a new [page] to the stack
291 /// 316 ///
292 /// It has the advantage of not needing context, 317 /// It has the advantage of not needing context,
@@ -337,6 +362,8 @@ extension GetNavigation on GetInterface { @@ -337,6 +362,8 @@ extension GetNavigation on GetInterface {
337 transitionDuration: duration ?? defaultDurationTransition)); 362 transitionDuration: duration ?? defaultDurationTransition));
338 } 363 }
339 364
  365 + /// **Navigation.pushAndRemoveUntil()** shortcut .<br><br>
  366 + ///
340 /// Push a [page] and pop several pages in the stack 367 /// Push a [page] and pop several pages in the stack
341 /// until [predicate] returns true. [predicate] is optional 368 /// until [predicate] returns true. [predicate] is optional
342 /// 369 ///
@@ -470,6 +497,7 @@ extension GetNavigation on GetInterface { @@ -470,6 +497,7 @@ extension GetNavigation on GetInterface {
470 )); 497 ));
471 } 498 }
472 499
  500 + /// Custom UI Dialog.
473 Future<T> defaultDialog<T>({ 501 Future<T> defaultDialog<T>({
474 String title = "Alert", 502 String title = "Alert",
475 Widget content, 503 Widget content,
@@ -884,7 +912,7 @@ extension GetNavigation on GetInterface { @@ -884,7 +912,7 @@ extension GetNavigation on GetInterface {
884 return key; 912 return key;
885 } 913 }
886 if (!keys.containsKey(k)) { 914 if (!keys.containsKey(k)) {
887 - throw 'route id not found'; 915 + throw 'Route id ($k) not found';
888 } 916 }
889 return keys[k]; 917 return keys[k];
890 } 918 }
@@ -892,7 +920,7 @@ extension GetNavigation on GetInterface { @@ -892,7 +920,7 @@ extension GetNavigation on GetInterface {
892 RouteSettings get routeSettings => settings; 920 RouteSettings get routeSettings => settings;
893 921
894 void setSettings(RouteSettings settings) { 922 void setSettings(RouteSettings settings) {
895 - settings = settings; 923 + this.settings = settings;
896 } 924 }
897 925
898 /// give current arguments 926 /// give current arguments
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
2 import 'package:get/src/navigation/routes/get_route.dart'; 2 import 'package:get/src/navigation/routes/get_route.dart';
3 3
4 -class GetPageMatch {  
5 - GetPageMatch(this.route);  
6 -  
7 - GetPage route;  
8 - Map<String, String> parameters = <String, String>{};  
9 -}  
10 -  
11 class ParseRouteTree { 4 class ParseRouteTree {
12 - final List<ParseRouteTreeNode> _nodes = <ParseRouteTreeNode>[]; 5 + final List<_ParseRouteTreeNode> _nodes = <_ParseRouteTreeNode>[];
13 6
14 // bool _hasDefaultRoute = false; 7 // bool _hasDefaultRoute = false;
15 8
@@ -20,7 +13,7 @@ class ParseRouteTree { @@ -20,7 +13,7 @@ class ParseRouteTree {
20 // if (_hasDefaultRoute) { 13 // if (_hasDefaultRoute) {
21 // throw ("Default route was already defined"); 14 // throw ("Default route was already defined");
22 // } 15 // }
23 - var node = ParseRouteTreeNode(path, ParseRouteTreeNodeType.component); 16 + var node = _ParseRouteTreeNode(path, _ParseRouteTreeNodeType.component);
24 node.routes = [route]; 17 node.routes = [route];
25 _nodes.add(node); 18 _nodes.add(node);
26 // _hasDefaultRoute = true; 19 // _hasDefaultRoute = true;
@@ -30,13 +23,13 @@ class ParseRouteTree { @@ -30,13 +23,13 @@ class ParseRouteTree {
30 path = path.substring(1); 23 path = path.substring(1);
31 } 24 }
32 List<String> pathComponents = path.split('/'); 25 List<String> pathComponents = path.split('/');
33 - ParseRouteTreeNode parent; 26 + _ParseRouteTreeNode parent;
34 for (int i = 0; i < pathComponents.length; i++) { 27 for (int i = 0; i < pathComponents.length; i++) {
35 String component = pathComponents[i]; 28 String component = pathComponents[i];
36 - ParseRouteTreeNode node = _nodeForComponent(component, parent); 29 + _ParseRouteTreeNode node = _nodeForComponent(component, parent);
37 if (node == null) { 30 if (node == null) {
38 - ParseRouteTreeNodeType type = _typeForComponent(component);  
39 - node = ParseRouteTreeNode(component, type); 31 + _ParseRouteTreeNodeType type = _typeForComponent(component);
  32 + node = _ParseRouteTreeNode(component, type);
40 node.parent = parent; 33 node.parent = parent;
41 if (parent == null) { 34 if (parent == null) {
42 _nodes.add(node); 35 _nodes.add(node);
@@ -55,7 +48,7 @@ class ParseRouteTree { @@ -55,7 +48,7 @@ class ParseRouteTree {
55 } 48 }
56 } 49 }
57 50
58 - GetPageMatch matchRoute(String path) { 51 + _GetPageMatch matchRoute(String path) {
59 String usePath = path; 52 String usePath = path;
60 if (usePath.startsWith("/")) { 53 if (usePath.startsWith("/")) {
61 usePath = path.substring(1); 54 usePath = path.substring(1);
@@ -68,14 +61,14 @@ class ParseRouteTree { @@ -68,14 +61,14 @@ class ParseRouteTree {
68 if (path == Navigator.defaultRouteName) { 61 if (path == Navigator.defaultRouteName) {
69 components = ["/"]; 62 components = ["/"];
70 } 63 }
71 - Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> nodeMatches =  
72 - <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{};  
73 - List<ParseRouteTreeNode> nodesToCheck = _nodes; 64 + Map<_ParseRouteTreeNode, _ParseRouteTreeNodeMatch> nodeMatches =
  65 + <_ParseRouteTreeNode, _ParseRouteTreeNodeMatch>{};
  66 + List<_ParseRouteTreeNode> nodesToCheck = _nodes;
74 for (String checkComponent in components) { 67 for (String checkComponent in components) {
75 - Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> currentMatches =  
76 - <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{};  
77 - List<ParseRouteTreeNode> nextNodes = <ParseRouteTreeNode>[];  
78 - for (ParseRouteTreeNode node in nodesToCheck) { 68 + Map<_ParseRouteTreeNode, _ParseRouteTreeNodeMatch> currentMatches =
  69 + <_ParseRouteTreeNode, _ParseRouteTreeNodeMatch>{};
  70 + List<_ParseRouteTreeNode> nextNodes = <_ParseRouteTreeNode>[];
  71 + for (_ParseRouteTreeNode node in nodesToCheck) {
79 String pathPart = checkComponent; 72 String pathPart = checkComponent;
80 Map<String, String> queryMap = {}; 73 Map<String, String> queryMap = {};
81 74
@@ -104,9 +97,9 @@ class ParseRouteTree { @@ -104,9 +97,9 @@ class ParseRouteTree {
104 97
105 bool isMatch = (node.part == pathPart || node.isParameter()); 98 bool isMatch = (node.part == pathPart || node.isParameter());
106 if (isMatch) { 99 if (isMatch) {
107 - ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent];  
108 - ParseRouteTreeNodeMatch match =  
109 - ParseRouteTreeNodeMatch.fromMatch(parentMatch, node); 100 + _ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent];
  101 + _ParseRouteTreeNodeMatch match =
  102 + _ParseRouteTreeNodeMatch.fromMatch(parentMatch, node);
110 103
111 // TODO: find a way to clean this implementation. 104 // TODO: find a way to clean this implementation.
112 match.parameters.addAll(uri.queryParameters); 105 match.parameters.addAll(uri.queryParameters);
@@ -131,16 +124,16 @@ class ParseRouteTree { @@ -131,16 +124,16 @@ class ParseRouteTree {
131 return null; 124 return null;
132 } 125 }
133 } 126 }
134 - List<ParseRouteTreeNodeMatch> matches = nodeMatches.values.toList(); 127 + List<_ParseRouteTreeNodeMatch> matches = nodeMatches.values.toList();
135 if (matches.length > 0) { 128 if (matches.length > 0) {
136 - ParseRouteTreeNodeMatch match = matches.first;  
137 - ParseRouteTreeNode nodeToUse = match.node; 129 + _ParseRouteTreeNodeMatch match = matches.first;
  130 + _ParseRouteTreeNode nodeToUse = match.node;
138 131
139 if (nodeToUse != null && 132 if (nodeToUse != null &&
140 nodeToUse.routes != null && 133 nodeToUse.routes != null &&
141 nodeToUse.routes.length > 0) { 134 nodeToUse.routes.length > 0) {
142 List<GetPage> routes = nodeToUse.routes; 135 List<GetPage> routes = nodeToUse.routes;
143 - GetPageMatch routeMatch = GetPageMatch(routes[0]); 136 + _GetPageMatch routeMatch = _GetPageMatch(routes[0]);
144 137
145 routeMatch.parameters = match.parameters; 138 routeMatch.parameters = match.parameters;
146 139
@@ -150,13 +143,13 @@ class ParseRouteTree { @@ -150,13 +143,13 @@ class ParseRouteTree {
150 return null; 143 return null;
151 } 144 }
152 145
153 - ParseRouteTreeNode _nodeForComponent(  
154 - String component, ParseRouteTreeNode parent) {  
155 - List<ParseRouteTreeNode> nodes = _nodes; 146 + _ParseRouteTreeNode _nodeForComponent(
  147 + String component, _ParseRouteTreeNode parent) {
  148 + List<_ParseRouteTreeNode> nodes = _nodes;
156 if (parent != null) { 149 if (parent != null) {
157 nodes = parent.nodes; 150 nodes = parent.nodes;
158 } 151 }
159 - for (ParseRouteTreeNode node in nodes) { 152 + for (_ParseRouteTreeNode node in nodes) {
160 if (node.part == component) { 153 if (node.part == component) {
161 return node; 154 return node;
162 } 155 }
@@ -164,10 +157,10 @@ class ParseRouteTree { @@ -164,10 +157,10 @@ class ParseRouteTree {
164 return null; 157 return null;
165 } 158 }
166 159
167 - ParseRouteTreeNodeType _typeForComponent(String component) {  
168 - ParseRouteTreeNodeType type = ParseRouteTreeNodeType.component; 160 + _ParseRouteTreeNodeType _typeForComponent(String component) {
  161 + _ParseRouteTreeNodeType type = _ParseRouteTreeNodeType.component;
169 if (_isParameterComponent(component)) { 162 if (_isParameterComponent(component)) {
170 - type = ParseRouteTreeNodeType.parameter; 163 + type = _ParseRouteTreeNodeType.parameter;
171 } 164 }
172 return type; 165 return type;
173 } 166 }
@@ -190,35 +183,43 @@ class ParseRouteTree { @@ -190,35 +183,43 @@ class ParseRouteTree {
190 } 183 }
191 } 184 }
192 185
193 -class ParseRouteTreeNodeMatch {  
194 - ParseRouteTreeNodeMatch(this.node); 186 +class _ParseRouteTreeNodeMatch {
  187 + _ParseRouteTreeNodeMatch(this.node);
195 188
196 - ParseRouteTreeNodeMatch.fromMatch(ParseRouteTreeNodeMatch match, this.node) { 189 + _ParseRouteTreeNodeMatch.fromMatch(
  190 + _ParseRouteTreeNodeMatch match, this.node) {
197 parameters = <String, String>{}; 191 parameters = <String, String>{};
198 if (match != null) { 192 if (match != null) {
199 parameters.addAll(match.parameters); 193 parameters.addAll(match.parameters);
200 } 194 }
201 } 195 }
202 196
203 - ParseRouteTreeNode node; 197 + _ParseRouteTreeNode node;
204 Map<String, String> parameters = <String, String>{}; 198 Map<String, String> parameters = <String, String>{};
205 } 199 }
206 200
207 -class ParseRouteTreeNode {  
208 - ParseRouteTreeNode(this.part, this.type); 201 +class _ParseRouteTreeNode {
  202 + _ParseRouteTreeNode(this.part, this.type);
209 203
210 String part; 204 String part;
211 - ParseRouteTreeNodeType type; 205 + _ParseRouteTreeNodeType type;
212 List<GetPage> routes = <GetPage>[]; 206 List<GetPage> routes = <GetPage>[];
213 - List<ParseRouteTreeNode> nodes = <ParseRouteTreeNode>[];  
214 - ParseRouteTreeNode parent; 207 + List<_ParseRouteTreeNode> nodes = <_ParseRouteTreeNode>[];
  208 + _ParseRouteTreeNode parent;
215 209
216 bool isParameter() { 210 bool isParameter() {
217 - return type == ParseRouteTreeNodeType.parameter; 211 + return type == _ParseRouteTreeNodeType.parameter;
218 } 212 }
219 } 213 }
220 214
221 -enum ParseRouteTreeNodeType { 215 +class _GetPageMatch {
  216 + _GetPageMatch(this.route);
  217 +
  218 + GetPage route;
  219 + Map<String, String> parameters = <String, String>{};
  220 +}
  221 +
  222 +enum _ParseRouteTreeNodeType {
222 component, 223 component,
223 parameter, 224 parameter,
224 } 225 }
@@ -38,11 +38,69 @@ class _RxImpl<T> implements RxInterface<T> { @@ -38,11 +38,69 @@ class _RxImpl<T> implements RxInterface<T> {
38 38
39 bool get canUpdate => _subscriptions.isNotEmpty; 39 bool get canUpdate => _subscriptions.isNotEmpty;
40 40
  41 + /// Makes this Rx looks like a function so you can update a new
  42 + /// value using [rx(someOtherValue)]. Practical to assign the Rx directly
  43 + /// to some Widget that has a signature ::onChange( value )
  44 + ///
  45 + /// Example:
  46 + /// ```
  47 + /// final myText = 'GetX rocks!'.obs;
  48 + ///
  49 + /// // in your Constructor, just to check it works :P
  50 + /// ever( myText, print ) ;
  51 + ///
  52 + /// // in your build(BuildContext) {
  53 + /// TextField(
  54 + // onChanged: myText,
  55 + // ),
  56 + ///```
41 T call([T v]) { 57 T call([T v]) {
42 if (v != null) this.value = v; 58 if (v != null) this.value = v;
43 return this.value; 59 return this.value;
44 } 60 }
45 61
  62 + /// Makes a direct update of [value] adding it to the Stream
  63 + /// useful when you make use of Rx for custom Types to referesh your UI.
  64 + ///
  65 + /// Sample:
  66 + /// ```
  67 + /// class Person {
  68 + /// String name, last;
  69 + /// int age;
  70 + /// Person({this.name, this.last, this.age});
  71 + /// @override
  72 + /// String toString() => '$name $last, $age years old';
  73 + /// }
  74 + ///
  75 + /// final person = Person(name: 'John', last: 'Doe', age: 18).obs;
  76 + /// person.value.name = 'Roi';
  77 + /// person.refresh();
  78 + /// print( person );
  79 + /// ```
  80 + void refresh() {
  81 + subject.add(value);
  82 + }
  83 +
  84 + /// Uses a callback to update [value] internally, similar to [refresh], but provides
  85 + /// the current value as the argument.
  86 + /// Makes sense for custom Rx types (like Models).
  87 + ///
  88 + /// Sample:
  89 + /// ```
  90 + /// class Person {
  91 + /// String name, last;
  92 + /// int age;
  93 + /// Person({this.name, this.last, this.age});
  94 + /// @override
  95 + /// String toString() => '$name $last, $age years old';
  96 + /// }
  97 + ///
  98 + /// final person = Person(name: 'John', last: 'Doe', age: 18).obs;
  99 + /// person.update((person) {
  100 + /// person.name = 'Roi';
  101 + /// });
  102 + /// print( person );
  103 + /// ```
46 void update(void fn(T value)) { 104 void update(void fn(T value)) {
47 fn(value); 105 fn(value);
48 subject.add(value); 106 subject.add(value);
@@ -3,20 +3,22 @@ import 'dart:async'; @@ -3,20 +3,22 @@ import 'dart:async';
3 import 'package:flutter/scheduler.dart'; 3 import 'package:flutter/scheduler.dart';
4 import 'package:get/src/state_manager/rx/rx_callbacks.dart'; 4 import 'package:get/src/state_manager/rx/rx_callbacks.dart';
5 5
  6 +/// This class is the foundation for all reactive (Rx) classes that makes Get
  7 +/// so powerful.
  8 +/// This interface is the contract that [_RxImpl]<[T]> uses in all it's
  9 +/// subclass.
6 abstract class RxInterface<T> { 10 abstract class RxInterface<T> {
7 RxInterface([T initial]); 11 RxInterface([T initial]);
8 12
9 - /// add listener to stream 13 + StreamController<T> subject;
  14 +
  15 + /// Adds a listener to stream
10 void addListener(Stream<T> rxGetx); 16 void addListener(Stream<T> rxGetx);
11 17
12 bool get canUpdate; 18 bool get canUpdate;
13 19
14 - /// close stream  
15 - void close() {  
16 - subject?.close();  
17 - }  
18 -  
19 - StreamController<T> subject; 20 + /// Closes the stream
  21 + void close() => subject?.close();
20 22
21 /// Calls [callback] with current value, when the value changes. 23 /// Calls [callback] with current value, when the value changes.
22 StreamSubscription<T> listen(ValueCallback<T> callback); 24 StreamSubscription<T> listen(ValueCallback<T> callback);
@@ -60,14 +62,40 @@ abstract class DisposableInterface { @@ -60,14 +62,40 @@ abstract class DisposableInterface {
60 SchedulerBinding.instance?.addPostFrameCallback((_) => onReady()); 62 SchedulerBinding.instance?.addPostFrameCallback((_) => onReady());
61 } 63 }
62 64
63 - /// Called Called immediately after the widget is allocated in memory. 65 + /// Called immediately after the widget is allocated in memory.
  66 + /// You might use this initialize something for the controller.
64 void onInit() async {} 67 void onInit() async {}
65 68
66 - /// Called after rendering the screen. It is the perfect place to enter navigation events,  
67 - /// be it snackbar, dialogs, or a new route. 69 + /// Called 1 frame after onInit(). It is the perfect place to enter navigation events,
  70 + /// like snackbar, dialogs, or a new route, or async request.
68 void onReady() async {} 71 void onReady() async {}
69 72
70 - /// Called before the onDelete method. onClose is used to close events  
71 - /// before the controller is destroyed, such as closing streams, for example.  
72 - onClose() async {} 73 + /// Called before [onDelete] method. [onClose] might be used to dispose resources
  74 + /// used by the controller. Like closing events, or streams before the controller is destroyed.
  75 + /// Or dispose objects that can potentially create some memory leaks,
  76 + /// like TextEditingControllers, AnimationControllers.
  77 + /// Might be useful as well to persist some data on disk.
  78 + void onClose() async {}
  79 +}
  80 +
  81 +/// Used like [SingleTickerProviderMixin] but only with Get Controllers.
  82 +/// Simplifies AnimationController creation inside GetxController.
  83 +///
  84 +/// Example:
  85 +///```
  86 +///class SplashController extends GetxController with SingleGetTickerProviderMixin {
  87 +/// AnimationController _ac;
  88 +///
  89 +/// @override
  90 +/// void onInit() {
  91 +/// final dur = const Duration(seconds: 2);
  92 +/// _ac = AnimationController.unbounded(duration: dur, vsync: this);
  93 +/// _ac.repeat();
  94 +/// _ac.addListener(() => print("Animation Controller value: ${_ac.value}"));
  95 +/// }
  96 +/// ...
  97 +/// ```
  98 +mixin SingleGetTickerProviderMixin on DisposableInterface
  99 + implements TickerProvider {
  100 + Ticker createTicker(TickerCallback onTick) => Ticker(onTick);
73 } 101 }
1 import 'dart:async'; 1 import 'dart:async';
2 2
  3 +/// This "function" class is the implementation of [debouncer()] Worker.
  4 +/// It calls the function passed after specified [delay] parameter.
  5 +/// Example:
  6 +/// ```
  7 +/// final delayed = Debouncer( delay: Duration( seconds: 1 )) ;
  8 +/// print( 'the next function will be called after 1 sec' );
  9 +/// delayed( () => print( 'called after 1 sec' ));
  10 +/// ```
3 class Debouncer { 11 class Debouncer {
4 final Duration delay; 12 final Duration delay;
5 Timer _timer; 13 Timer _timer;
6 14
7 Debouncer({this.delay}); 15 Debouncer({this.delay});
8 16
9 - call(void Function() action) { 17 + void call(void Function() action) {
10 _timer?.cancel(); 18 _timer?.cancel();
11 _timer = Timer(delay, action); 19 _timer = Timer(delay, action);
12 } 20 }
  21 +
  22 + /// Notifies if the delayed call is active.
  23 + bool get isRunning => _timer?.isActive ?? false;
  24 +
  25 + /// Cancel the current delayed call.
  26 + void cancel() => _timer?.cancel();
13 } 27 }