Committed by
GitHub
Merge pull request #523 from roipeker/master
General cleanup, more docs.
Showing
7 changed files
with
305 additions
and
96 deletions
@@ -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 | } |
-
Please register or login to post a comment