Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ final subscription = eventBus
.respond<EventA>(responderA) // Subscribe to EventA
.respond<EventB>(responderB) // Subscribe to EventB
.respond<EventC>(responderC) // Subscribe to EventC
.respond(genericResponder); // Subscribe to EventA EventB EventC and any other event on event bus
.respond<EventA?>(responderNullableA) // Subscribe to EventA and any null
.respond<EventB?>(responderNullableB) // Subscribe to EventB and any null
.respond(genericResponder); // Subscribe to EventA EventB EventC null and any other event on event bus

// Generic Responder could be useful for monitoring, logging or diagnosis purpose, probably will be hardly used to take action to event

Expand Down
26 changes: 13 additions & 13 deletions example/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) => EventBusWidget(
child: MaterialApp(
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
Expand All @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget {
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
MyHomePage({Key? key, required this.title}) : super(key: key);

// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
Expand All @@ -43,23 +43,23 @@ class MyHomePage extends StatefulWidget {
_MyHomePageState createState() => _MyHomePageState();
}

class InreaseCounterEvent {}
class IncreaseCounterEvent {}

class IncreaseCounterButton extends StatelessWidget {
@override
Widget build(BuildContext context) => FloatingActionButton(
onPressed: () {
EventBus.publishTo(context, InreaseCounterEvent());
},
tooltip: 'Increment',
child: Icon(Icons.add),
);
onPressed: () {
EventBus.publishTo(context, IncreaseCounterEvent());
},
tooltip: 'Increment',
child: Icon(Icons.add),
);
}

class _MyHomePageState extends Interactor<MyHomePage> {
int _counter = 0;

void _incrementCounter(InreaseCounterEvent event) {
void _incrementCounter(IncreaseCounterEvent event) {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
Expand Down Expand Up @@ -109,17 +109,17 @@ class _MyHomePageState extends Interactor<MyHomePage> {
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton:
IncreaseCounterButton(), // This trailing comma makes auto-formatting nicer for build methods.
IncreaseCounterButton(), // This trailing comma makes auto-formatting nicer for build methods.
);
}

@override
Subscription subscribeEvents(EventBus eventBus) =>
eventBus.respond<InreaseCounterEvent>(_incrementCounter);
eventBus.respond<IncreaseCounterEvent>(_incrementCounter);
}
2 changes: 1 addition & 1 deletion lib/BuilderInteractor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'Interactor.dart';
abstract class BuilderInteractorWidget extends StatefulWidget {
final WidgetBuilder childBuilder;

const BuilderInteractorWidget({Key key, @required this.childBuilder})
const BuilderInteractorWidget({Key? key, required this.childBuilder})
: super(key: key);
}

Expand Down
16 changes: 8 additions & 8 deletions lib/EventBus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ class EventBus {
EventBus.customController(this._streamController);

/// Create an event bus with default dart StreamController.
/// You can use [sync] to indentify whether the event bus should be sync or async, by default it is async.
/// You can use [sync] to identify whether the event bus should be sync or async, by default it is async.
/// For more detail, check [Stream] document.
EventBus({bool sync = false})
: _streamController = StreamController.broadcast(sync: sync);
: _streamController = StreamController<dynamic>.broadcast(sync: sync);

Stream get _stream => _streamController.stream;

/// Publish an event to all corresponding responders via EventBus
void publish(event) {
void publish(dynamic event) {
_streamController.add(event);
}

Expand Down Expand Up @@ -58,7 +58,7 @@ class EventBus {
/// ```
/// EventBus.of(context).publish(event);
/// ```
static void publishTo(BuildContext context, event) =>
static void publishTo(BuildContext context, dynamic event) =>
of(context).publish(event);
}

Expand Down Expand Up @@ -88,18 +88,18 @@ class EventBusWidget extends InheritedWidget {
/// is `synchronized` or `asynchronized`, default to `asynchronized`.
/// If [eventBus] is given, [sync] is ignored
///
/// The [eventBus] param chould be useful if you want to access eventBus from widget who hold [EventBusWidget],
/// The [eventBus] param should be useful if you want to access eventBus from widget who hold [EventBusWidget],
/// or you are using custom [StreamController] in Event Bus.
EventBusWidget(
{Key key, @required Widget child, EventBus eventBus, bool sync = false})
{Key? key, required Widget child, EventBus? eventBus, bool sync = false})
: eventBus = eventBus ?? EventBus(sync: sync),
super(key: key, child: child);

@override
bool updateShouldNotify(EventBusWidget oldWidget) =>
eventBus != oldWidget.eventBus;

/// Find the closeset [EventBusWidget] from ancester tree.
/// Find the closest [EventBusWidget] from ancestor tree.
static EventBusWidget of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<EventBusWidget>();
context.dependOnInheritedWidgetOfExactType<EventBusWidget>()!;
}
4 changes: 2 additions & 2 deletions lib/Interactor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import 'EventBus.dart';
/// }
/// ```
abstract class Interactor<T extends StatefulWidget> extends State<T> {
Subscription _subscription;
Subscription? _subscription;

/// [EventBus] provided by ancestor [EventBusWidget]
/// Cannot not be accessed in [initState] or [dispose], as state has not yet or had been removed from element tree.
Expand All @@ -42,7 +42,7 @@ abstract class Interactor<T extends StatefulWidget> extends State<T> {

@override
void dispose() {
_subscription.dispose();
_subscription?.dispose();

super.dispose();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/ProxyInteractor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'Interactor.dart';
abstract class ProxyInteractorWidget extends StatefulWidget {
final Widget child;

const ProxyInteractorWidget({Key key, @required this.child})
const ProxyInteractorWidget({Key? key, required this.child})
: super(key: key);
}

Expand Down
13 changes: 9 additions & 4 deletions lib/Subscription.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Subscription {
final Stream _stream;

/// Subscriptions that registered to event bus
final List<StreamSubscription> subscriptions = List();
final subscriptions = <StreamSubscription>[];

/// Create the subscription
///
Expand All @@ -18,8 +18,13 @@ class Subscription {
/// Returns an instance that indicates there is no subscription
factory Subscription.empty() => const _EmptySubscription();

Stream<T> _cast<T>() =>
(T == dynamic) ? _stream : _stream.where((event) => event is T).cast<T>();
Stream<T> _cast<T>() {
if((T == dynamic)) {
return _stream.cast();
}

return _stream.where((event) => event is T).cast<T>();
}

/// Register a [responder] to event bus for the event type [T].
/// If [T] is omitted or given as `dyanmic`, it listens to all events that publised on [EventBus].
Expand Down Expand Up @@ -51,7 +56,7 @@ class Subscription {

class _EmptySubscription implements Subscription {
static final List<StreamSubscription> emptyList =
List.unmodifiable(<StreamSubscription>[]);
List.unmodifiable(<StreamSubscription>[]);

const _EmptySubscription();

Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ homepage: https://github.com/timnew/flutter_event_bus/
repository: https://github.com/timnew/flutter_event_bus/

environment:
sdk: '>=2.1.0 <3.0.0'
sdk: '>=2.12.0 <3.0.0'

dependencies:
flutter:
Expand All @@ -17,6 +17,6 @@ dev_dependencies:
flutter_test:
sdk: flutter

mockito: ^4.1.1
mockito: ^5.0.10

flutter:
120 changes: 114 additions & 6 deletions test/event_bus_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ void main() {
test("should publish and respond to event", () {
final eventBus = EventBus(sync: true);

String capturedEvent;
late String capturedEvent;

eventBus.respond<String>((String event) {
capturedEvent = event;
Expand All @@ -18,11 +18,25 @@ void main() {
expect(capturedEvent, "event");
});

test("should publish and respond to nullable event", () {
final eventBus = EventBus(sync: true);

String? capturedEvent = 'some-random-value';

eventBus.respond<String?>((String? event) {
capturedEvent = event;
});

eventBus.publish(null);

expect(capturedEvent, null);
});

test("should respond to event by type", () {
final eventBus = EventBus(sync: true);

List<String> capturedStrings = List();
List<int> capturedNumbers = List();
final capturedStrings = <String>[];
final capturedNumbers = <int>[];

eventBus.respond<String>((String event) {
capturedStrings.add(event);
Expand All @@ -42,22 +56,116 @@ void main() {
expect(capturedNumbers, [2, 4]);
});

test("should not recieve event after disposed subscription", () {
test("should respond to dynamic events", () {
final eventBus = EventBus(sync: true);

List<String> capturedEvents = List();
final capturedDynamics = <dynamic>[];
final capturedStrings = <String>[];

eventBus.respond<dynamic>((dynamic event) {
capturedDynamics.add(event);
});

eventBus.respond<String>((String event) {
capturedStrings.add(event);
});

eventBus.publish("1");
eventBus.publish(2);
eventBus.publish(null);
eventBus.publish(true);
eventBus.publish("3");

expect(capturedDynamics, ["1", 2, null, true, "3"]);
expect(capturedStrings, ["1", "3"]);
});

test("should respond to nullable events by type", () {
final eventBus = EventBus(sync: true);

final capturedStrings = <String?>[];
final capturedNumbers = <int?>[];

eventBus.respond<String?>((String? event) {
capturedStrings.add(event);
});

eventBus.respond<int?>((int? event) {
capturedNumbers.add(event);
});

eventBus.publish("1");
eventBus.publish(2);
eventBus.publish(null);

eventBus.publish("3");
eventBus.publish(4);
eventBus.publish(null);

final subscription = eventBus.respond<String>((String event) {
expect(capturedStrings, ["1", null, "3", null]);
expect(capturedNumbers, [2, null, 4, null]);
});

test("should respond to some nullable events and some not-nullable events by type", () {
final eventBus = EventBus(sync: true);

final capturedStrings = <String?>[];
final capturedNumbers = <int>[];

eventBus.respond<String?>((String? event) {
capturedStrings.add(event);
});

eventBus.respond<int>((int event) {
capturedNumbers.add(event);
});

eventBus.publish("1");
eventBus.publish(2);
eventBus.publish(null);

eventBus.publish("3");
eventBus.publish(4);
eventBus.publish(null);

expect(capturedStrings, ["1", null, "3", null]);
expect(capturedNumbers, [2, 4]);
});

test("should not receive event after disposed subscription", () {
final eventBus = EventBus(sync: true);

final capturedEvents = <String?>[];

final subscription = eventBus.respond<String?>((String? event) {
capturedEvents.add(event);
});

eventBus.publish("1");
eventBus.publish("2");
eventBus.publish(null);

subscription.dispose();

eventBus.publish("3");
eventBus.publish("4");
eventBus.publish(null);

expect(capturedEvents, ["1", "2", null]);
});

test("should respond to event by type ignoring nulls", () {
final eventBus = EventBus(sync: true);

final capturedEvents = <String>[];

eventBus.respond<String>((String event) {
capturedEvents.add(event);
});

eventBus.publish("1");
eventBus.publish("2");
eventBus.publish(null);

expect(capturedEvents, ["1", "2"]);
});
Expand Down
Loading