11/// Base interface for Events
22abstract class NyEvent {
3- final Map < Type , NyListener > listeners = {};
3+ final Map listeners = {};
44}
55
66/// Base class for listeners
@@ -17,7 +17,134 @@ class NyListener {
1717
1818 /// Handle the payload from the event
1919 /// The [event] argument provides a Map of the data
20- /// event<ChatCreated>(data: {"chat": Chat()});
21- /// E.g. [event] = {"chat":"Chat instance"}
22- Future <dynamic > handle (Map ? event) async {}
20+ Future handle (Map ? event) async {}
21+ }
22+
23+ class NyEventBus {
24+ static final NyEventBus _instance = NyEventBus ._internal ();
25+ factory NyEventBus () => _instance;
26+ NyEventBus ._internal ();
27+
28+ final Map <Type , List <NyListener >> _subscriptions = {};
29+
30+ void on < T extends NyEvent > (NyListener listener) {
31+ _subscriptions[T ] ?? = [];
32+ if (! _subscriptions[T ]! .contains (listener)) {
33+ _subscriptions[T ]! .add (listener);
34+ }
35+ }
36+
37+ void off <T extends NyEvent >(NyListener listener) {
38+ if (_subscriptions.containsKey (T )) {
39+ _subscriptions[T ]! .remove (listener);
40+ if (_subscriptions[T ]! .isEmpty) {
41+ _subscriptions.remove (T );
42+ }
43+ }
44+ }
45+
46+ Future <void > broadcast (NyEvent event, [Map ? params]) async {
47+ final Type eventType = event.runtimeType;
48+
49+ if (_subscriptions.containsKey (eventType)) {
50+ final listeners = List <NyListener >.from (_subscriptions[eventType]! );
51+
52+ for (var listener in listeners) {
53+ // Skip if listener was already removed (could happen if returning false in a callback)
54+ if (! _subscriptions.containsKey (eventType) ||
55+ ! _subscriptions[eventType]! .contains (listener)) {
56+ continue ;
57+ }
58+
59+ listener.setEvent (event);
60+ dynamic result = await listener.handle (params);
61+
62+ // Check if we should stop propagation
63+ if (result != null && result == false ) {
64+ break ;
65+ }
66+ }
67+ }
68+ }
69+
70+ // Add this method to remove a listener without needing to specify the type
71+ void removeListener (NyListener listener) {
72+ for (var type in _subscriptions.keys.toList ()) {
73+ if (_subscriptions[type]! .contains (listener)) {
74+ _subscriptions[type]! .remove (listener);
75+ if (_subscriptions[type]! .isEmpty) {
76+ _subscriptions.remove (type);
77+ }
78+ break ; // Assuming a listener is only registered once
79+ }
80+ }
81+ }
82+ }
83+
84+ /// Subscription handle that can be used to cancel listening
85+ class NyEventSubscription <T extends NyEvent > {
86+ final NyListener _listener;
87+ bool _active = true ;
88+
89+ NyEventSubscription (this ._listener);
90+
91+ /// Cancel this subscription
92+ void cancel () {
93+ if (_active) {
94+ NyEventBus ().off <T >(_listener);
95+ _active = false ;
96+ }
97+ }
98+
99+ bool get isActive => _active;
100+ }
101+
102+ /// Extension on NyEvent that adds the new functionality
103+ extension NyEventExtension on NyEvent {
104+ // Fire method that works with both existing and new listeners
105+ Future <void > fireAll (Map ? params, {bool broadcast = true }) async {
106+ // Execute existing listeners using current pattern
107+ for (var listener in listeners.values.toList ()) {
108+ if (listener is NyListener ) {
109+ listener.setEvent (this );
110+ dynamic result = await listener.handle (params);
111+ if (result != null && result == false ) {
112+ return ; // Early termination if a listener returns false
113+ }
114+ }
115+ }
116+
117+ if (! broadcast) return ;
118+ // Execute dynamically registered listeners
119+ await NyEventBus ().broadcast (this , params);
120+ }
121+ }
122+
123+ class NyEventCallbackListener extends NyListener {
124+ final Function (Map ? data) callback;
125+ bool _shouldCancel = false ;
126+
127+ NyEventCallbackListener (this .callback);
128+
129+ @override
130+ Future handle (Map ? event) async {
131+ final result = callback (event);
132+
133+ // If callback returns false, flag this subscription for cancellation
134+ if (result != null && result == false ) {
135+ _shouldCancel = true ;
136+ // Use the new method that doesn't require type parameter
137+ NyEventBus ().removeListener (this );
138+ return false ;
139+ }
140+ return result;
141+ }
142+
143+ bool get shouldCancel => _shouldCancel;
144+ }
145+
146+ NyEventSubscription listenOn <E extends NyEvent >(Function (Map ? data) callback) {
147+ final listener = NyEventCallbackListener (callback);
148+ NyEventBus ().on < E > (listener);
149+ return NyEventSubscription <E >(listener);
23150}
0 commit comments