- Clean up more code on GetInstance() and added more docs.
- Fixes issue #521. Still needs to be tested, is a partial solution and i believe parse_route.dart requires a much deeper cleanup. - Added a new BindingsBuilder(), to simplify the Bindings generation without the need to use a custom class. - Modified several operators in _RxImpl and subclasses. rx.toString() solves to rx.value.toString(), and in all Rx >>= works as assignment, also specific operator overloads were added to RX versions of List, String, double, num, int.
Showing
4 changed files
with
229 additions
and
72 deletions
1 | -import 'package:flutter/cupertino.dart'; | ||
2 | import 'package:get/src/core/log.dart'; | 1 | import 'package:get/src/core/log.dart'; |
3 | import 'package:get/src/navigation/root/smart_management.dart'; | 2 | import 'package:get/src/navigation/root/smart_management.dart'; |
4 | import 'package:get/src/state_manager/rx/rx_interface.dart'; | 3 | import 'package:get/src/state_manager/rx/rx_interface.dart'; |
@@ -11,28 +10,26 @@ class GetConfig { | @@ -11,28 +10,26 @@ class GetConfig { | ||
11 | static String currentRoute; | 10 | static String currentRoute; |
12 | } | 11 | } |
13 | 12 | ||
14 | -class Lazy { | ||
15 | - Lazy(this.builder, this.fenix); | ||
16 | - bool fenix; | ||
17 | - FcBuilderFunc builder; | ||
18 | -} | ||
19 | - | ||
20 | class GetInstance { | 13 | class GetInstance { |
21 | - factory GetInstance() { | ||
22 | - if (_getInstance == null) _getInstance = GetInstance._(); | ||
23 | - return _getInstance; | ||
24 | - } | 14 | + factory GetInstance() => _getInstance ??= GetInstance._(); |
25 | const GetInstance._(); | 15 | const GetInstance._(); |
26 | static GetInstance _getInstance; | 16 | static GetInstance _getInstance; |
27 | 17 | ||
28 | - static Map<dynamic, dynamic> _singl = {}; | ||
29 | - static Map<dynamic, Lazy> _factory = {}; | 18 | + /// Holds references to every registered Instance when using |
19 | + /// Get.[put] | ||
20 | + static Map<String, _FcBuilder> _singl = {}; | ||
21 | + | ||
22 | + /// Holds a reference to every registered callback when using | ||
23 | + /// Get.[lazyPut] | ||
24 | + static Map<String, _Lazy> _factory = {}; | ||
25 | + | ||
30 | static Map<String, String> _routesKey = {}; | 26 | static Map<String, String> _routesKey = {}; |
31 | 27 | ||
28 | + static GetQueue _queue = GetQueue(); | ||
29 | + | ||
32 | void lazyPut<S>(FcBuilderFunc builder, {String tag, bool fenix = false}) { | 30 | void lazyPut<S>(FcBuilderFunc builder, {String tag, bool fenix = false}) { |
33 | String key = _getKey(S, tag); | 31 | String key = _getKey(S, tag); |
34 | - | ||
35 | - _factory.putIfAbsent(key, () => Lazy(builder, fenix)); | 32 | + _factory.putIfAbsent(key, () => _Lazy(builder, fenix)); |
36 | } | 33 | } |
37 | 34 | ||
38 | Future<S> putAsync<S>(FcBuilderFuncAsync<S> builder, | 35 | Future<S> putAsync<S>(FcBuilderFuncAsync<S> builder, |
@@ -40,7 +37,7 @@ class GetInstance { | @@ -40,7 +37,7 @@ class GetInstance { | ||
40 | return put<S>(await builder(), tag: tag, permanent: permanent); | 37 | return put<S>(await builder(), tag: tag, permanent: permanent); |
41 | } | 38 | } |
42 | 39 | ||
43 | - /// Injects a Instance [S] in [GetInstance]. | 40 | + /// Injects an instance <[S]> in memory to be globally accessible. |
44 | /// | 41 | /// |
45 | /// No need to define the generic type <[S]> as it's inferred from the [dependency] | 42 | /// No need to define the generic type <[S]> as it's inferred from the [dependency] |
46 | /// | 43 | /// |
@@ -48,7 +45,6 @@ class GetInstance { | @@ -48,7 +45,6 @@ class GetInstance { | ||
48 | /// - [tag] optionally, use a [tag] as an "id" to create multiple records of the same Type<[S]> | 45 | /// - [tag] optionally, use a [tag] as an "id" to create multiple records of the same Type<[S]> |
49 | /// - [permanent] keeps the Instance in memory, not following [GetConfig.smartManagement] | 46 | /// - [permanent] keeps the Instance in memory, not following [GetConfig.smartManagement] |
50 | /// rules. | 47 | /// rules. |
51 | - /// | ||
52 | S put<S>( | 48 | S put<S>( |
53 | S dependency, { | 49 | S dependency, { |
54 | String tag, | 50 | String tag, |
@@ -73,7 +69,6 @@ class GetInstance { | @@ -73,7 +69,6 @@ class GetInstance { | ||
73 | /// Repl a = find(); | 69 | /// Repl a = find(); |
74 | /// Repl b = find(); | 70 | /// Repl b = find(); |
75 | /// print(a==b); (false)``` | 71 | /// print(a==b); (false)``` |
76 | - /// | ||
77 | void create<S>( | 72 | void create<S>( |
78 | FcBuilderFunc<S> builder, { | 73 | FcBuilderFunc<S> builder, { |
79 | String name, | 74 | String name, |
@@ -84,7 +79,6 @@ class GetInstance { | @@ -84,7 +79,6 @@ class GetInstance { | ||
84 | } | 79 | } |
85 | 80 | ||
86 | /// Injects the Instance [S] builder into the [_singleton] HashMap. | 81 | /// Injects the Instance [S] builder into the [_singleton] HashMap. |
87 | - /// | ||
88 | void _insert<S>({ | 82 | void _insert<S>({ |
89 | bool isSingleton, | 83 | bool isSingleton, |
90 | String name, | 84 | String name, |
@@ -94,13 +88,12 @@ class GetInstance { | @@ -94,13 +88,12 @@ class GetInstance { | ||
94 | assert(builder != null); | 88 | assert(builder != null); |
95 | final key = _getKey(S, name); | 89 | final key = _getKey(S, name); |
96 | _singl.putIfAbsent( | 90 | _singl.putIfAbsent( |
97 | - key, () => FcBuilder<S>(isSingleton, builder, permanent, false)); | 91 | + key, () => _FcBuilder<S>(isSingleton, builder, permanent, false)); |
98 | } | 92 | } |
99 | 93 | ||
100 | /// Clears from memory registered Instances associated with [routeName] when | 94 | /// Clears from memory registered Instances associated with [routeName] when |
101 | /// using [GetConfig.smartManagement] as [SmartManagement.full] or [SmartManagement.keepFactory] | 95 | /// using [GetConfig.smartManagement] as [SmartManagement.full] or [SmartManagement.keepFactory] |
102 | /// Meant for internal usage of [GetPageRoute] and [GetDialogRoute] | 96 | /// Meant for internal usage of [GetPageRoute] and [GetDialogRoute] |
103 | - /// | ||
104 | Future<void> removeDependencyByRoute(String routeName) async { | 97 | Future<void> removeDependencyByRoute(String routeName) async { |
105 | final keysToRemove = <String>[]; | 98 | final keysToRemove = <String>[]; |
106 | _routesKey.forEach((key, value) { | 99 | _routesKey.forEach((key, value) { |
@@ -123,7 +116,6 @@ class GetInstance { | @@ -123,7 +116,6 @@ class GetInstance { | ||
123 | /// Optionally associating the current Route to the lifetime of the instance, | 116 | /// Optionally associating the current Route to the lifetime of the instance, |
124 | /// if [GetConfig.smartManagement] is marked as [SmartManagement.full] or | 117 | /// if [GetConfig.smartManagement] is marked as [SmartManagement.full] or |
125 | /// [GetConfig.keepFactory] | 118 | /// [GetConfig.keepFactory] |
126 | - /// | ||
127 | bool _initDependencies<S>({String name}) { | 119 | bool _initDependencies<S>({String name}) { |
128 | final key = _getKey(S, name); | 120 | final key = _getKey(S, name); |
129 | bool isInit = _singl[key].isInit; | 121 | bool isInit = _singl[key].isInit; |
@@ -139,23 +131,23 @@ class GetInstance { | @@ -139,23 +131,23 @@ class GetInstance { | ||
139 | 131 | ||
140 | /// Links a Class instance [S] (or [tag]) to the current route. | 132 | /// Links a Class instance [S] (or [tag]) to the current route. |
141 | /// Requires usage of [GetMaterialApp]. | 133 | /// Requires usage of [GetMaterialApp]. |
142 | - /// | ||
143 | void _registerRouteInstance<S>({String tag}) { | 134 | void _registerRouteInstance<S>({String tag}) { |
144 | _routesKey.putIfAbsent(_getKey(S, tag), () => GetConfig.currentRoute); | 135 | _routesKey.putIfAbsent(_getKey(S, tag), () => GetConfig.currentRoute); |
145 | } | 136 | } |
146 | 137 | ||
147 | - /// Finds and returns a Class instance [S] (or tag) without further processing. | 138 | + /// Finds and returns a Instance<[S]> (or [tag]) without further processing. |
148 | S findByType<S>(Type type, {String tag}) { | 139 | S findByType<S>(Type type, {String tag}) { |
149 | String key = _getKey(type, tag); | 140 | String key = _getKey(type, tag); |
150 | return _singl[key].getDependency() as S; | 141 | return _singl[key].getDependency() as S; |
151 | } | 142 | } |
152 | 143 | ||
144 | + /// Initializes the controller | ||
153 | void _startController<S>({String tag}) { | 145 | void _startController<S>({String tag}) { |
154 | final key = _getKey(S, tag); | 146 | final key = _getKey(S, tag); |
155 | final i = _singl[key].getDependency(); | 147 | final i = _singl[key].getDependency(); |
156 | if (i is DisposableInterface) { | 148 | if (i is DisposableInterface) { |
157 | i.onStart(); | 149 | i.onStart(); |
158 | - GetConfig.log('$key has been initialized'); | 150 | + GetConfig.log('"$key" has been initialized'); |
159 | } | 151 | } |
160 | } | 152 | } |
161 | 153 | ||
@@ -180,20 +172,20 @@ class GetInstance { | @@ -180,20 +172,20 @@ class GetInstance { | ||
180 | // } | 172 | // } |
181 | // } | 173 | // } |
182 | 174 | ||
183 | - /// Finds a instance of the required Class<[S]> (or [tag]) | ||
184 | - /// In the case of using Get.[create], it will create an instance | ||
185 | - /// each time you call [find] | ||
186 | - /// | 175 | + /// Finds the registered type <[S]> (or [tag]) |
176 | + /// In case of using Get.[create] to register a type <[S]> or [tag], it will create an instance | ||
177 | + /// each time you call [find]. | ||
178 | + /// If the registered type <[S]> (or [tag]) is a Controller, it will initialize | ||
179 | + /// it's lifecycle. | ||
187 | S find<S>({String tag}) { | 180 | S find<S>({String tag}) { |
188 | String key = _getKey(S, tag); | 181 | String key = _getKey(S, tag); |
189 | - | ||
190 | if (isRegistered<S>(tag: tag)) { | 182 | if (isRegistered<S>(tag: tag)) { |
191 | - FcBuilder builder = _singl[key] as FcBuilder; | 183 | + _FcBuilder builder = _singl[key] as _FcBuilder; |
192 | if (builder == null) { | 184 | if (builder == null) { |
193 | if (tag == null) { | 185 | if (tag == null) { |
194 | - throw "class ${S.toString()} is not register"; | 186 | + throw 'Class "$S" is not register'; |
195 | } else { | 187 | } else { |
196 | - throw "class ${S.toString()} with tag '$tag' is not register"; | 188 | + throw 'Class "$S" with tag "$tag" is not register'; |
197 | } | 189 | } |
198 | } | 190 | } |
199 | _initDependencies<S>(name: tag); | 191 | _initDependencies<S>(name: tag); |
@@ -201,9 +193,11 @@ class GetInstance { | @@ -201,9 +193,11 @@ class GetInstance { | ||
201 | return _singl[key].getDependency() as S; | 193 | return _singl[key].getDependency() as S; |
202 | } else { | 194 | } else { |
203 | if (!_factory.containsKey(key)) | 195 | if (!_factory.containsKey(key)) |
204 | - throw "$S not found. You need call put<$S>($S()) before"; | 196 | + throw '"$S" not found. You need to call "Get.put<$S>($S())"'; |
197 | + | ||
198 | + // TODO: This message is not clear | ||
199 | + GetConfig.log('"$S" instance was created at that time'); | ||
205 | 200 | ||
206 | - GetConfig.log('$S instance was created at that time'); | ||
207 | S _value = put<S>(_factory[key].builder() as S); | 201 | S _value = put<S>(_factory[key].builder() as S); |
208 | 202 | ||
209 | _initDependencies<S>(name: tag); | 203 | _initDependencies<S>(name: tag); |
@@ -234,8 +228,6 @@ class GetInstance { | @@ -234,8 +228,6 @@ class GetInstance { | ||
234 | return true; | 228 | return true; |
235 | } | 229 | } |
236 | 230 | ||
237 | - static GetQueue queue = GetQueue(); | ||
238 | - | ||
239 | // Future<bool> delete<S>({String tag, String key, bool force = false}) async { | 231 | // Future<bool> delete<S>({String tag, String key, bool force = false}) async { |
240 | // final s = await queue | 232 | // final s = await queue |
241 | // .add<bool>(() async => dele<S>(tag: tag, key: key, force: force)); | 233 | // .add<bool>(() async => dele<S>(tag: tag, key: key, force: force)); |
@@ -247,17 +239,16 @@ class GetInstance { | @@ -247,17 +239,16 @@ class GetInstance { | ||
247 | Future<bool> delete<S>({String tag, String key, bool force = false}) async { | 239 | Future<bool> delete<S>({String tag, String key, bool force = false}) async { |
248 | final newKey = key ?? _getKey(S, tag); | 240 | final newKey = key ?? _getKey(S, tag); |
249 | 241 | ||
250 | - return queue.add<bool>(() async { | 242 | + return _queue.add<bool>(() async { |
251 | if (!_singl.containsKey(newKey)) { | 243 | if (!_singl.containsKey(newKey)) { |
252 | - | ||
253 | - GetConfig.log('Instance $newKey already been removed.', isError: true); | 244 | + GetConfig.log('Instance "$newKey" already removed.', isError: true); |
254 | return false; | 245 | return false; |
255 | } | 246 | } |
256 | 247 | ||
257 | - FcBuilder builder = _singl[newKey] as FcBuilder; | 248 | + _FcBuilder builder = _singl[newKey] as _FcBuilder; |
258 | if (builder.permanent && !force) { | 249 | if (builder.permanent && !force) { |
259 | GetConfig.log( | 250 | GetConfig.log( |
260 | - '[$newKey] has been marked as permanent, SmartManagement is not authorized to delete it.', | 251 | + '"$newKey" has been marked as permanent, SmartManagement is not authorized to delete it.', |
261 | isError: true); | 252 | isError: true); |
262 | return false; | 253 | return false; |
263 | } | 254 | } |
@@ -268,14 +259,14 @@ class GetInstance { | @@ -268,14 +259,14 @@ class GetInstance { | ||
268 | } | 259 | } |
269 | if (i is DisposableInterface) { | 260 | if (i is DisposableInterface) { |
270 | await i.onClose(); | 261 | await i.onClose(); |
271 | - GetConfig.log('onClose of $newKey called'); | 262 | + GetConfig.log('"$newKey" onClose() called'); |
272 | } | 263 | } |
273 | 264 | ||
274 | _singl.removeWhere((oldKey, value) => (oldKey == newKey)); | 265 | _singl.removeWhere((oldKey, value) => (oldKey == newKey)); |
275 | if (_singl.containsKey(newKey)) { | 266 | if (_singl.containsKey(newKey)) { |
276 | - GetConfig.log('error on remove object $newKey', isError: true); | 267 | + GetConfig.log('Error removing object "$newKey"', isError: true); |
277 | } else { | 268 | } else { |
278 | - GetConfig.log('$newKey deleted from memory'); | 269 | + GetConfig.log('"$newKey" deleted from memory'); |
279 | } | 270 | } |
280 | // _routesKey?.remove(key); | 271 | // _routesKey?.remove(key); |
281 | return true; | 272 | return true; |
@@ -293,23 +284,37 @@ typedef FcBuilderFunc<S> = S Function(); | @@ -293,23 +284,37 @@ typedef FcBuilderFunc<S> = S Function(); | ||
293 | 284 | ||
294 | typedef FcBuilderFuncAsync<S> = Future<S> Function(); | 285 | typedef FcBuilderFuncAsync<S> = Future<S> Function(); |
295 | 286 | ||
296 | -class FcBuilder<S> { | 287 | +/// Internal class to register instances with Get.[put]<[S]>(). |
288 | +class _FcBuilder<S> { | ||
289 | + /// Marks the Builder as a single instance. | ||
290 | + /// For reusing [dependency] instead of [builderFunc] | ||
297 | bool isSingleton; | 291 | bool isSingleton; |
298 | - FcBuilderFunc builderFunc; | 292 | + |
293 | + /// Stores the actual object instance when [isSingleton]=true. | ||
299 | S dependency; | 294 | S dependency; |
295 | + | ||
296 | + /// Generates (and regenerates) the instance when [isSingleton]=false. | ||
297 | + /// Usually used by factory methods | ||
298 | + FcBuilderFunc<S> builderFunc; | ||
299 | + | ||
300 | + /// Flag to persist the instance in memory, | ||
301 | + /// without considering [GetConfig.smartManagement] | ||
300 | bool permanent = false; | 302 | bool permanent = false; |
303 | + | ||
301 | bool isInit = false; | 304 | bool isInit = false; |
302 | 305 | ||
303 | - FcBuilder(this.isSingleton, this.builderFunc, this.permanent, this.isInit); | 306 | + _FcBuilder(this.isSingleton, this.builderFunc, this.permanent, this.isInit); |
304 | 307 | ||
308 | + /// Gets the actual instance by it's [builderFunc] or the persisted instance. | ||
305 | S getDependency() { | 309 | S getDependency() { |
306 | - if (isSingleton) { | ||
307 | - if (dependency == null) { | ||
308 | - dependency = builderFunc() as S; | ||
309 | - } | ||
310 | - return dependency; | ||
311 | - } else { | ||
312 | - return builderFunc() as S; | ||
313 | - } | 310 | + return isSingleton ? dependency ??= builderFunc() : builderFunc(); |
314 | } | 311 | } |
315 | } | 312 | } |
313 | + | ||
314 | +/// Internal class to register a future instance with [lazyPut], | ||
315 | +/// keeps a reference to the callback to be called. | ||
316 | +class _Lazy { | ||
317 | + bool fenix; | ||
318 | + FcBuilderFunc builder; | ||
319 | + _Lazy(this.builder, this.fenix); | ||
320 | +} |
@@ -10,6 +10,7 @@ class GetPageMatch { | @@ -10,6 +10,7 @@ class GetPageMatch { | ||
10 | 10 | ||
11 | class ParseRouteTree { | 11 | class ParseRouteTree { |
12 | final List<ParseRouteTreeNode> _nodes = <ParseRouteTreeNode>[]; | 12 | final List<ParseRouteTreeNode> _nodes = <ParseRouteTreeNode>[]; |
13 | + | ||
13 | // bool _hasDefaultRoute = false; | 14 | // bool _hasDefaultRoute = false; |
14 | 15 | ||
15 | void addRoute(GetPage route) { | 16 | void addRoute(GetPage route) { |
@@ -59,11 +60,14 @@ class ParseRouteTree { | @@ -59,11 +60,14 @@ class ParseRouteTree { | ||
59 | if (usePath.startsWith("/")) { | 60 | if (usePath.startsWith("/")) { |
60 | usePath = path.substring(1); | 61 | usePath = path.substring(1); |
61 | } | 62 | } |
62 | - List<String> components = usePath.split("/"); | 63 | + |
64 | + // should take off url parameters first.. | ||
65 | + final uri = Uri.tryParse(usePath); | ||
66 | +// List<String> components = usePath.split("/"); | ||
67 | + List<String> components = uri.pathSegments; | ||
63 | if (path == Navigator.defaultRouteName) { | 68 | if (path == Navigator.defaultRouteName) { |
64 | components = ["/"]; | 69 | components = ["/"]; |
65 | } | 70 | } |
66 | - | ||
67 | Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> nodeMatches = | 71 | Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> nodeMatches = |
68 | <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{}; | 72 | <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{}; |
69 | List<ParseRouteTreeNode> nodesToCheck = _nodes; | 73 | List<ParseRouteTreeNode> nodesToCheck = _nodes; |
@@ -103,6 +107,10 @@ class ParseRouteTree { | @@ -103,6 +107,10 @@ class ParseRouteTree { | ||
103 | ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent]; | 107 | ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent]; |
104 | ParseRouteTreeNodeMatch match = | 108 | ParseRouteTreeNodeMatch match = |
105 | ParseRouteTreeNodeMatch.fromMatch(parentMatch, node); | 109 | ParseRouteTreeNodeMatch.fromMatch(parentMatch, node); |
110 | + | ||
111 | + // TODO: find a way to clean this implementation. | ||
112 | + match.parameters.addAll(uri.queryParameters); | ||
113 | + | ||
106 | if (node.isParameter()) { | 114 | if (node.isParameter()) { |
107 | String paramKey = node.part.substring(1); | 115 | String paramKey = node.part.substring(1); |
108 | match.parameters[paramKey] = pathPart; | 116 | match.parameters[paramKey] = pathPart; |
1 | +/// [Bindings] should be extended or implemented. | ||
2 | +/// When using [GetMaterialApp], all [GetPage]s and navigation methods (like Get.to()) | ||
3 | +/// have a [binding] property that takes an instance of Bindings to manage the | ||
4 | +/// dependencies() (via [Get.put()]) for the Route you are opening. | ||
1 | abstract class Bindings { | 5 | abstract class Bindings { |
2 | void dependencies(); | 6 | void dependencies(); |
3 | } | 7 | } |
4 | 8 | ||
9 | +/// Simplifies Bindings generation from a single callback. | ||
10 | +/// To avoid the creation of a custom Binding instance per route. | ||
11 | +/// | ||
12 | +/// Example: | ||
13 | +/// ``` | ||
14 | +/// GetPage( | ||
15 | +/// name: '/', | ||
16 | +/// page: () => Home(), | ||
17 | +/// binding: BindingsBuilder(() => Get.put(HomeController())), | ||
18 | +/// ), | ||
19 | +/// ```` | ||
20 | +class BindingsBuilder extends Bindings { | ||
21 | + /// Register your dependencies in the [builder] callback. | ||
22 | + final Function() builder; | ||
23 | + | ||
24 | + BindingsBuilder(this.builder); | ||
25 | + | ||
26 | + @override | ||
27 | + void dependencies() { | ||
28 | + builder(); | ||
29 | + } | ||
30 | +} | ||
31 | + | ||
5 | // abstract class INavigation {} | 32 | // abstract class INavigation {} |
6 | // typedef Snack = Function(); | 33 | // typedef Snack = Function(); |
7 | // typedef Modal = Function(); | 34 | // typedef Modal = Function(); |
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | import 'dart:collection'; | 2 | import 'dart:collection'; |
3 | + | ||
3 | import 'rx_interface.dart'; | 4 | import 'rx_interface.dart'; |
4 | 5 | ||
6 | +RxInterface getObs; | ||
7 | + | ||
8 | +typedef bool Condition(); | ||
9 | + | ||
5 | class _RxImpl<T> implements RxInterface<T> { | 10 | class _RxImpl<T> implements RxInterface<T> { |
6 | StreamController<T> subject = StreamController<T>.broadcast(); | 11 | StreamController<T> subject = StreamController<T>.broadcast(); |
7 | HashMap<Stream<T>, StreamSubscription> _subscriptions = | 12 | HashMap<Stream<T>, StreamSubscription> _subscriptions = |
@@ -15,14 +20,26 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -15,14 +20,26 @@ class _RxImpl<T> implements RxInterface<T> { | ||
15 | return _value; | 20 | return _value; |
16 | } | 21 | } |
17 | 22 | ||
18 | - bool get canUpdate { | ||
19 | - return _subscriptions.length > 0; | 23 | + /// Common to all Types [T], this operator overloading is using for |
24 | + /// assignment, same as rx.value | ||
25 | + /// | ||
26 | + /// Example: | ||
27 | + /// ``` | ||
28 | + /// var counter = 0.obs ; | ||
29 | + /// counter >>= 3; // same as counter.value=3; | ||
30 | + /// print(counter); // calls .toString() now | ||
31 | + /// ``` | ||
32 | + /// | ||
33 | + /// WARNING: still WIP, needs testing! | ||
34 | + _RxImpl<T> operator >>(T val) { | ||
35 | + subject.add(value = val); | ||
36 | + return this; | ||
20 | } | 37 | } |
21 | 38 | ||
39 | + bool get canUpdate => _subscriptions.isNotEmpty; | ||
40 | + | ||
22 | T call([T v]) { | 41 | T call([T v]) { |
23 | - if (v != null) { | ||
24 | - this.value = v; | ||
25 | - } | 42 | + if (v != null) this.value = v; |
26 | return this.value; | 43 | return this.value; |
27 | } | 44 | } |
28 | 45 | ||
@@ -33,15 +50,24 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -33,15 +50,24 @@ class _RxImpl<T> implements RxInterface<T> { | ||
33 | 50 | ||
34 | String get string => value.toString(); | 51 | String get string => value.toString(); |
35 | 52 | ||
36 | - close() { | ||
37 | - _subscriptions.forEach((observable, subscription) { | ||
38 | - subscription.cancel(); | ||
39 | - }); | 53 | + @override |
54 | + String toString() => value.toString(); | ||
55 | + | ||
56 | + /// This equality override works for _RxImpl instances and the internal values. | ||
57 | + bool operator ==(o) { | ||
58 | + // Todo, find a common implementation for the hashCode of different Types. | ||
59 | + if (o is T) return _value == o; | ||
60 | + if (o is _RxImpl<T>) return _value == o.value; | ||
61 | + return false; | ||
62 | + } | ||
63 | + | ||
64 | + void close() { | ||
65 | + _subscriptions.forEach((observable, subscription) => subscription.cancel()); | ||
40 | _subscriptions.clear(); | 66 | _subscriptions.clear(); |
41 | subject.close(); | 67 | subject.close(); |
42 | } | 68 | } |
43 | 69 | ||
44 | - addListener(Stream<T> rxGetx) { | 70 | + void addListener(Stream<T> rxGetx) { |
45 | if (_subscriptions.containsKey(rxGetx)) { | 71 | if (_subscriptions.containsKey(rxGetx)) { |
46 | return; | 72 | return; |
47 | } | 73 | } |
@@ -286,6 +312,16 @@ class RxList<E> extends Iterable<E> implements RxInterface<List<E>> { | @@ -286,6 +312,16 @@ class RxList<E> extends Iterable<E> implements RxInterface<List<E>> { | ||
286 | subject.add(_list); | 312 | subject.add(_list); |
287 | } | 313 | } |
288 | 314 | ||
315 | + /// Special override to push() element(s) in a reactive way | ||
316 | + /// inside the List, | ||
317 | + RxList<E> operator +(val) { | ||
318 | + if (val is Iterable) | ||
319 | + subject.add(_list..addAll(val)); | ||
320 | + else | ||
321 | + subject.add(_list..add(val)); | ||
322 | + return this; | ||
323 | + } | ||
324 | + | ||
289 | E operator [](int index) { | 325 | E operator [](int index) { |
290 | return value[index]; | 326 | return value[index]; |
291 | } | 327 | } |
@@ -428,10 +464,6 @@ class RxList<E> extends Iterable<E> implements RxInterface<List<E>> { | @@ -428,10 +464,6 @@ class RxList<E> extends Iterable<E> implements RxInterface<List<E>> { | ||
428 | List<E> _list = <E>[]; | 464 | List<E> _list = <E>[]; |
429 | } | 465 | } |
430 | 466 | ||
431 | -RxInterface getObs; | ||
432 | - | ||
433 | -typedef bool Condition(); | ||
434 | - | ||
435 | class RxBool extends _RxImpl<bool> { | 467 | class RxBool extends _RxImpl<bool> { |
436 | RxBool([bool initial]) { | 468 | RxBool([bool initial]) { |
437 | _value = initial; | 469 | _value = initial; |
@@ -442,24 +474,109 @@ class RxDouble extends _RxImpl<double> { | @@ -442,24 +474,109 @@ class RxDouble extends _RxImpl<double> { | ||
442 | RxDouble([double initial]) { | 474 | RxDouble([double initial]) { |
443 | _value = initial; | 475 | _value = initial; |
444 | } | 476 | } |
477 | + | ||
478 | + RxDouble operator +(double val) { | ||
479 | + subject.add(value += val); | ||
480 | + return this; | ||
481 | + } | ||
482 | + | ||
483 | + RxDouble operator -(double val) { | ||
484 | + subject.add(value -= val); | ||
485 | + return this; | ||
486 | + } | ||
487 | + | ||
488 | + RxDouble operator /(double val) { | ||
489 | + subject.add(value /= val); | ||
490 | + return this; | ||
491 | + } | ||
492 | + | ||
493 | + RxDouble operator *(double val) { | ||
494 | + subject.add(value *= val); | ||
495 | + return this; | ||
496 | + } | ||
445 | } | 497 | } |
446 | 498 | ||
447 | class RxNum extends _RxImpl<num> { | 499 | class RxNum extends _RxImpl<num> { |
448 | RxNum([num initial]) { | 500 | RxNum([num initial]) { |
449 | _value = initial; | 501 | _value = initial; |
450 | } | 502 | } |
503 | + | ||
504 | + RxNum operator >>(num val) { | ||
505 | + subject.add(value = val); | ||
506 | + return this; | ||
507 | + } | ||
508 | + | ||
509 | + RxNum operator +(num val) { | ||
510 | + subject.add(value += val); | ||
511 | + return this; | ||
512 | + } | ||
513 | + | ||
514 | + RxNum operator -(num val) { | ||
515 | + subject.add(value -= val); | ||
516 | + return this; | ||
517 | + } | ||
518 | + | ||
519 | + RxNum operator /(num val) { | ||
520 | + subject.add(value /= val); | ||
521 | + return this; | ||
522 | + } | ||
523 | + | ||
524 | + RxNum operator *(num val) { | ||
525 | + subject.add(value *= val); | ||
526 | + return this; | ||
527 | + } | ||
451 | } | 528 | } |
452 | 529 | ||
453 | class RxString extends _RxImpl<String> { | 530 | class RxString extends _RxImpl<String> { |
454 | RxString([String initial]) { | 531 | RxString([String initial]) { |
455 | _value = initial; | 532 | _value = initial; |
456 | } | 533 | } |
534 | + | ||
535 | + RxString operator >>(String val) { | ||
536 | + subject.add(value = val); | ||
537 | + return this; | ||
538 | + } | ||
539 | + | ||
540 | + RxString operator +(String val) { | ||
541 | + subject.add(value += val); | ||
542 | + return this; | ||
543 | + } | ||
544 | + | ||
545 | + RxString operator *(int val) { | ||
546 | + subject.add(value *= val); | ||
547 | + return this; | ||
548 | + } | ||
457 | } | 549 | } |
458 | 550 | ||
459 | class RxInt extends _RxImpl<int> { | 551 | class RxInt extends _RxImpl<int> { |
460 | RxInt([int initial]) { | 552 | RxInt([int initial]) { |
461 | _value = initial; | 553 | _value = initial; |
462 | } | 554 | } |
555 | + | ||
556 | + RxInt operator >>(int val) { | ||
557 | + subject.add(value = val); | ||
558 | + return this; | ||
559 | + } | ||
560 | + | ||
561 | + RxInt operator +(int val) { | ||
562 | + subject.add(value += val); | ||
563 | + return this; | ||
564 | + } | ||
565 | + | ||
566 | + RxInt operator -(int val) { | ||
567 | + subject.add(value -= val); | ||
568 | + return this; | ||
569 | + } | ||
570 | + | ||
571 | + RxInt operator /(int val) { | ||
572 | + subject.add(value ~/= val); | ||
573 | + return this; | ||
574 | + } | ||
575 | + | ||
576 | + RxInt operator *(int val) { | ||
577 | + subject.add(value *= val); | ||
578 | + return this; | ||
579 | + } | ||
463 | } | 580 | } |
464 | 581 | ||
465 | class Rx<T> extends _RxImpl<T> { | 582 | class Rx<T> extends _RxImpl<T> { |
-
Please register or login to post a comment