Skip to content

Instantly share code, notes, and snippets.

@rrousselGit
Created April 14, 2020 21:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rrousselGit/cd0f5a0dd5f77f2df58343ed999b0fe4 to your computer and use it in GitHub Desktop.
Save rrousselGit/cd0f5a0dd5f77f2df58343ed999b0fe4 to your computer and use it in GitHub Desktop.
extension AsValueListenable<T> on Stream<T> {
/// Converts a [Stream] to a [ValueListenable]
///
/// The internal [StreamSubscription] is cancelled when
/// all listeners added to [ValueListenable] are removed.
/// Keep this in mind as this could cause issues with
/// single-subscription streams.
ValueListenable<T> asValueListenable(T initialValue) {
return _StreamValueListenable(this, initialValue);
}
}
class _StreamValueListenable<T> extends ValueNotifier<T> {
_StreamValueListenable(this.stream, T initialValue) : super(initialValue);
final Stream<T> stream;
StreamSubscription<T> subscription;
@override
void addListener(VoidCallback listener) {
subscription ??= stream.listen((event) {
value = event;
});
super.addListener(listener);
}
@override
void removeListener(VoidCallback listener) {
super.removeListener(listener);
if (!hasListeners && subscription != null) {
subscription.cancel();
subscription = null;
}
}
}
@chimon2000
Copy link

Would the ValueNotifier version look something like the following?

import 'dart:async';
import 'package:state_notifier/state_notifier.dart';

extension AsValueListenable<T> on Stream<T> {
  /// Converts a [Stream] to a [StateNotifier]
  ///
  /// The internal [StreamSubscription] is cancelled when
  /// all listeners added to [StateNotifier] are removed.
  /// Keep this in mind as this could cause issues with
  /// single-subscription streams.
  StateNotifier<T> asStateNotifier(T initialValue) {
    return _StreamValueListenable(this, initialValue);
  }
}

class _StreamValueListenable<T> extends StateNotifier<T> {
  _StreamValueListenable(this.stream, T initialValue) : super(initialValue);

  final Stream<T> stream;

  StreamSubscription<T> subscription;

  @override
  RemoveListener addListener(
    Listener<T> listener, {
    bool fireImmediately = true,
  }) {
    subscription ??= stream.listen((event) {
      state = event;
    });

    return super.addListener(listener);
  }

  @override
  void dispose() {
    subscription.cancel();
    subscription = null;
    super.dispose();
  }
}

@rrousselGit
Copy link
Author

You may want to override the RemoveListener function to unsubscribe too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment