Skip to content

Instantly share code, notes, and snippets.

@danielgomezrico
Last active October 19, 2023 16:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielgomezrico/361e862af6a2f3c78141bee9ec546044 to your computer and use it in GitHub Desktop.
Save danielgomezrico/361e862af6a2f3c78141bee9ec546044 to your computer and use it in GitHub Desktop.
Dart/Flutter - Extensions to emit ChangeNotifier changes as a Stream, very useful for unit testing
/// Function to get the changed value everytime
typedef GetChangeFunction<T> = T Function();
extension AsStream<T> on ChangeNotifier {
Stream<T> statusAsStream(GetChangeFunction<T> getChange) {
final controller = StreamController<T>();
// Redirect status changes into the Stream
final notify = () => controller.add(getChange());
addListener(notify);
controller.onCancel = () => removeListener(notify);
// As this is intended for tests it should close if no emitions were done
// in x period of time to avoid a never ending test
Future.delayed(Duration(seconds: 5)).then((value) => controller.close());
return controller.stream;
}
StreamController<T> statusAsStreamController(GetChangeFunction<T> getChange) {
final controller = StreamController<T>();
// Redirect status changes into the Stream
final notify = () => controller.add(getChange());
addListener(notify);
controller.onCancel = () => removeListener(notify);
return controller;
}
}
// Your ViewModel abstraction
abstract class ViewModel<S> with ChangeNotifier {
S _status;
S get status => _status;
set status(S value) {
_status = value;
notifyListeners();
}
}
// Cleaner extensions
extension AsStream<T> on ViewModel<T> {
Stream<T> statusStream() {
final controller = StreamController<T>();
// Redirect status changes into the Stream
final notify = () => controller.add(status);
addListener(notify);
controller.onCancel = () => removeListener(notify);
// Timeout to cancel the stream if no changes
Future.delayed(Duration(seconds: 5)).then((value) => controller.close());
return controller.stream;
}
StreamController<T> statusStreamController() {
final controller = StreamController<T>();
// Redirect status changes into the Stream
final notify = () => controller.add(status);
addListener(notify);
controller.onCancel = () => removeListener(notify);
return controller;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment