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