fix comment, adds Rx features.
- small comment fix (https://github.com/jonataslaw/getx/pull/560#commitcomment-42045326) - added `RxBool.toggle()`as an easy shortcut for switching true/false values. - added `_RxImp.nil()` to easily set the value to `null` (`nil` comes from LISP :P) seems to be a useful sometimes, for instance if using `RxString` in `TextField.decoration.errorText` is the only way to avoid the "error state". - adds missing docs to Rx classes.
Showing
1 changed file
with
54 additions
and
1 deletions
@@ -3,8 +3,12 @@ import 'dart:collection'; | @@ -3,8 +3,12 @@ import 'dart:collection'; | ||
3 | 3 | ||
4 | import '../rx_core/rx_interface.dart'; | 4 | import '../rx_core/rx_interface.dart'; |
5 | 5 | ||
6 | + | ||
7 | +/// global object that registers against `GetX` and `Obx`, and allows the reactivity | ||
8 | +/// of those `Widgets` and Rx values. | ||
6 | RxInterface getObs; | 9 | RxInterface getObs; |
7 | 10 | ||
11 | +/// Base Rx class that manages all the stream logic for any Type. | ||
8 | class _RxImpl<T> implements RxInterface<T> { | 12 | class _RxImpl<T> implements RxInterface<T> { |
9 | StreamController<T> subject = StreamController<T>.broadcast(); | 13 | StreamController<T> subject = StreamController<T>.broadcast(); |
10 | final _subscriptions = HashMap<Stream<T>, StreamSubscription>(); | 14 | final _subscriptions = HashMap<Stream<T>, StreamSubscription>(); |
@@ -17,7 +21,7 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -17,7 +21,7 @@ class _RxImpl<T> implements RxInterface<T> { | ||
17 | /// Example: | 21 | /// Example: |
18 | /// ``` | 22 | /// ``` |
19 | /// var counter = 0.obs ; | 23 | /// var counter = 0.obs ; |
20 | - /// counter >>= 3; // same as counter.value=3; | 24 | + /// counter <<= 3; // same as counter.value=3; |
21 | /// print(counter); // calls .toString() now | 25 | /// print(counter); // calls .toString() now |
22 | /// ``` | 26 | /// ``` |
23 | /// | 27 | /// |
@@ -99,11 +103,27 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -99,11 +103,27 @@ class _RxImpl<T> implements RxInterface<T> { | ||
99 | subject.add(_value); | 103 | subject.add(_value); |
100 | } | 104 | } |
101 | 105 | ||
106 | + /// updates the value to [null] and adds it to the Stream. | ||
107 | + /// Even with null-safety coming, is still an important feature to support, as | ||
108 | + /// [call()] doesn't accept [null] values. For instance, | ||
109 | + /// [InputDecoration.errorText] has to be null to not show the "error state". | ||
110 | + /// | ||
111 | + /// Sample: | ||
112 | + /// ``` | ||
113 | + /// final inputError = ''.obs..nil(); | ||
114 | + /// print('${inputError.runtimeType}: $inputError'); // outputs > RxString: null | ||
115 | + /// ``` | ||
116 | + void nil() { | ||
117 | + subject.add(_value=null); | ||
118 | + } | ||
119 | + | ||
120 | + /// Same as `toString()` but using a getter. | ||
102 | String get string => value.toString(); | 121 | String get string => value.toString(); |
103 | 122 | ||
104 | @override | 123 | @override |
105 | String toString() => value.toString(); | 124 | String toString() => value.toString(); |
106 | 125 | ||
126 | + /// Returns the json representation of `value`. | ||
107 | dynamic toJson() => value; | 127 | dynamic toJson() => value; |
108 | 128 | ||
109 | /// This equality override works for _RxImpl instances and the internal | 129 | /// This equality override works for _RxImpl instances and the internal |
@@ -121,12 +141,15 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -121,12 +141,15 @@ class _RxImpl<T> implements RxInterface<T> { | ||
121 | // ignore: avoid_equals_and_hash_code_on_mutable_classes | 141 | // ignore: avoid_equals_and_hash_code_on_mutable_classes |
122 | int get hashCode => _value.hashCode; | 142 | int get hashCode => _value.hashCode; |
123 | 143 | ||
144 | + /// Closes the subscriptions for this Rx, releasing the resources. | ||
124 | void close() { | 145 | void close() { |
125 | _subscriptions.forEach((observable, subscription) => subscription.cancel()); | 146 | _subscriptions.forEach((observable, subscription) => subscription.cancel()); |
126 | _subscriptions.clear(); | 147 | _subscriptions.clear(); |
127 | subject.close(); | 148 | subject.close(); |
128 | } | 149 | } |
129 | 150 | ||
151 | + /// This is an internal method. | ||
152 | + /// Subscribe to changes on the inner stream. | ||
130 | void addListener(Stream<T> rxGetx) { | 153 | void addListener(Stream<T> rxGetx) { |
131 | if (_subscriptions.containsKey(rxGetx)) { | 154 | if (_subscriptions.containsKey(rxGetx)) { |
132 | return; | 155 | return; |
@@ -138,6 +161,9 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -138,6 +161,9 @@ class _RxImpl<T> implements RxInterface<T> { | ||
138 | 161 | ||
139 | bool firstRebuild = true; | 162 | bool firstRebuild = true; |
140 | 163 | ||
164 | + | ||
165 | + /// Updates the [value] and adds it to the stream, updating the observer | ||
166 | + /// Widget, only it's different from the previous value. | ||
141 | set value(T val) { | 167 | set value(T val) { |
142 | if (_value == val && !firstRebuild) return; | 168 | if (_value == val && !firstRebuild) return; |
143 | firstRebuild = false; | 169 | firstRebuild = false; |
@@ -145,6 +171,7 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -145,6 +171,7 @@ class _RxImpl<T> implements RxInterface<T> { | ||
145 | subject.add(_value); | 171 | subject.add(_value); |
146 | } | 172 | } |
147 | 173 | ||
174 | + /// Returns the current [value] | ||
148 | T get value { | 175 | T get value { |
149 | if (getObs != null) { | 176 | if (getObs != null) { |
150 | getObs.addListener(subject.stream); | 177 | getObs.addListener(subject.stream); |
@@ -158,11 +185,15 @@ class _RxImpl<T> implements RxInterface<T> { | @@ -158,11 +185,15 @@ class _RxImpl<T> implements RxInterface<T> { | ||
158 | {Function onError, void Function() onDone, bool cancelOnError}) => | 185 | {Function onError, void Function() onDone, bool cancelOnError}) => |
159 | stream.listen(onData, onError: onError, onDone: onDone); | 186 | stream.listen(onData, onError: onError, onDone: onDone); |
160 | 187 | ||
188 | + | ||
189 | + /// Binds an existing stream to this Rx to keep the values in sync. | ||
161 | void bindStream(Stream<T> stream) => stream.listen((va) => value = va); | 190 | void bindStream(Stream<T> stream) => stream.listen((va) => value = va); |
162 | 191 | ||
163 | Stream<R> map<R>(R mapper(T data)) => stream.map(mapper); | 192 | Stream<R> map<R>(R mapper(T data)) => stream.map(mapper); |
164 | } | 193 | } |
165 | 194 | ||
195 | + | ||
196 | +/// Rx class for `bool` Type. | ||
166 | class RxBool extends _RxImpl<bool> { | 197 | class RxBool extends _RxImpl<bool> { |
167 | RxBool([bool initial]) { | 198 | RxBool([bool initial]) { |
168 | _value = initial; | 199 | _value = initial; |
@@ -174,11 +205,20 @@ class RxBool extends _RxImpl<bool> { | @@ -174,11 +205,20 @@ class RxBool extends _RxImpl<bool> { | ||
174 | 205 | ||
175 | bool operator ^(bool other) => !other == value; | 206 | bool operator ^(bool other) => !other == value; |
176 | 207 | ||
208 | + /// Toggles the bool [value] between false and true. | ||
209 | + /// A shortcut for `flag.value = !flag.value;` | ||
210 | + RxBool toggle() { | ||
211 | + subject.add(_value = !_value); | ||
212 | + return this; | ||
213 | + } | ||
214 | + | ||
177 | String toString() { | 215 | String toString() { |
178 | return value ? "true" : "false"; | 216 | return value ? "true" : "false"; |
179 | } | 217 | } |
180 | } | 218 | } |
181 | 219 | ||
220 | +/// Base Rx class for `num` Types (`double` and `int`) as mostly share the same | ||
221 | +/// operator overload, we centralize the common code here. | ||
182 | abstract class _BaseRxNum<T> extends _RxImpl<num> { | 222 | abstract class _BaseRxNum<T> extends _RxImpl<num> { |
183 | _BaseRxNum operator +(num val) { | 223 | _BaseRxNum operator +(num val) { |
184 | subject.add(_value += val); | 224 | subject.add(_value += val); |
@@ -216,18 +256,21 @@ abstract class _BaseRxNum<T> extends _RxImpl<num> { | @@ -216,18 +256,21 @@ abstract class _BaseRxNum<T> extends _RxImpl<num> { | ||
216 | bool operator >(num other) => _value > other; | 256 | bool operator >(num other) => _value > other; |
217 | } | 257 | } |
218 | 258 | ||
259 | +/// Rx class for `double` Type. | ||
219 | class RxDouble extends _BaseRxNum<double> { | 260 | class RxDouble extends _BaseRxNum<double> { |
220 | RxDouble([double initial]) { | 261 | RxDouble([double initial]) { |
221 | _value = initial; | 262 | _value = initial; |
222 | } | 263 | } |
223 | } | 264 | } |
224 | 265 | ||
266 | +/// Rx class for `num` Type. | ||
225 | class RxNum extends _BaseRxNum<num> { | 267 | class RxNum extends _BaseRxNum<num> { |
226 | RxNum([num initial]) { | 268 | RxNum([num initial]) { |
227 | _value = initial; | 269 | _value = initial; |
228 | } | 270 | } |
229 | } | 271 | } |
230 | 272 | ||
273 | +/// Rx class for `String` Type. | ||
231 | class RxString extends _RxImpl<String> { | 274 | class RxString extends _RxImpl<String> { |
232 | RxString([String initial]) { | 275 | RxString([String initial]) { |
233 | _value = initial; | 276 | _value = initial; |
@@ -244,12 +287,17 @@ class RxString extends _RxImpl<String> { | @@ -244,12 +287,17 @@ class RxString extends _RxImpl<String> { | ||
244 | } | 287 | } |
245 | } | 288 | } |
246 | 289 | ||
290 | +/// Rx class for `int` Type. | ||
247 | class RxInt extends _BaseRxNum<int> { | 291 | class RxInt extends _BaseRxNum<int> { |
248 | RxInt([int initial]) { | 292 | RxInt([int initial]) { |
249 | _value = initial; | 293 | _value = initial; |
250 | } | 294 | } |
251 | } | 295 | } |
252 | 296 | ||
297 | + | ||
298 | +/// Foundation class used for custom `Types` outside the common native Dart types. | ||
299 | +/// For example, any custom "Model" class, like User().obs will use `Rx` as | ||
300 | +/// wrapper. | ||
253 | class Rx<T> extends _RxImpl<T> { | 301 | class Rx<T> extends _RxImpl<T> { |
254 | Rx([T initial]) { | 302 | Rx([T initial]) { |
255 | _value = initial; | 303 | _value = initial; |
@@ -262,21 +310,26 @@ class Rx<T> extends _RxImpl<T> { | @@ -262,21 +310,26 @@ class Rx<T> extends _RxImpl<T> { | ||
262 | } | 310 | } |
263 | 311 | ||
264 | extension StringExtension on String { | 312 | extension StringExtension on String { |
313 | + /// Returns a `RxString` with [this] `String` as initial value. | ||
265 | RxString get obs => RxString(this); | 314 | RxString get obs => RxString(this); |
266 | } | 315 | } |
267 | 316 | ||
268 | extension IntExtension on int { | 317 | extension IntExtension on int { |
318 | + /// Returns a `RxInt` with [this] `int` as initial value. | ||
269 | RxInt get obs => RxInt(this); | 319 | RxInt get obs => RxInt(this); |
270 | } | 320 | } |
271 | 321 | ||
272 | extension DoubleExtension on double { | 322 | extension DoubleExtension on double { |
323 | + /// Returns a `RxDouble` with [this] `double` as initial value. | ||
273 | RxDouble get obs => RxDouble(this); | 324 | RxDouble get obs => RxDouble(this); |
274 | } | 325 | } |
275 | 326 | ||
276 | extension BoolExtension on bool { | 327 | extension BoolExtension on bool { |
328 | + /// Returns a `RxBool` with [this] `bool` as initial value. | ||
277 | RxBool get obs => RxBool(this); | 329 | RxBool get obs => RxBool(this); |
278 | } | 330 | } |
279 | 331 | ||
280 | extension RxT<T> on T { | 332 | extension RxT<T> on T { |
333 | + /// Returns a `Rx` instace with [this] `T` as initial value. | ||
281 | Rx<T> get obs => Rx<T>(this); | 334 | Rx<T> get obs => Rx<T>(this); |
282 | } | 335 | } |
-
Please register or login to post a comment