| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import 'package:flutter/foundation.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef EventCallback<Data> = Future<dynamic> Function(Data data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | abstract class BaseEvent<EventType, Data> { | 
					
						
							|  |  |  |   EventType type; | 
					
						
							|  |  |  |   Data data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |   /// Constructor.
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   BaseEvent(this.type, this.data); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |   /// Consume this event.
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |   @visibleForTesting | 
					
						
							|  |  |  |   Future<dynamic> consume() async { | 
					
						
							|  |  |  |     final cb = findCallback(type); | 
					
						
							|  |  |  |     if (cb == null) { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return cb(data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   EventCallback<Data>? findCallback(EventType type); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | abstract class BaseEventLoop<EventType, Data> { | 
					
						
							|  |  |  |   final List<BaseEvent<EventType, Data>> _evts = []; | 
					
						
							|  |  |  |   Timer? _timer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   List<BaseEvent<EventType, Data>> get evts => _evts; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<void> onReady() async { | 
					
						
							|  |  |  |     // Poll every 100ms.
 | 
					
						
							|  |  |  |     _timer = Timer.periodic(Duration(milliseconds: 100), _handleTimer); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /// An Event is about to be consumed.
 | 
					
						
							|  |  |  |   Future<void> onPreConsume(BaseEvent<EventType, Data> evt) async {} | 
					
						
							|  |  |  |   /// An Event was consumed.
 | 
					
						
							|  |  |  |   Future<void> onPostConsume(BaseEvent<EventType, Data> evt) async {} | 
					
						
							|  |  |  |   /// Events are all handled and cleared.
 | 
					
						
							|  |  |  |   Future<void> onEventsClear() async {} | 
					
						
							|  |  |  |   /// Events start to consume.
 | 
					
						
							|  |  |  |   Future<void> onEventsStartConsuming() async {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<void> _handleTimer(Timer timer) async { | 
					
						
							|  |  |  |       if (_evts.isEmpty) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       timer.cancel(); | 
					
						
							|  |  |  |       _timer = null; | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |       // Handle the logic.
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |       await onEventsStartConsuming(); | 
					
						
							|  |  |  |       while (_evts.isNotEmpty) { | 
					
						
							|  |  |  |         final evt = _evts.first; | 
					
						
							|  |  |  |         _evts.remove(evt); | 
					
						
							|  |  |  |         await onPreConsume(evt); | 
					
						
							|  |  |  |         await evt.consume(); | 
					
						
							|  |  |  |         await onPostConsume(evt); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       await onEventsClear(); | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |       // Now events are all processed.
 | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |       _timer = Timer.periodic(Duration(milliseconds: 100), _handleTimer); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<void> close() async { | 
					
						
							|  |  |  |     _timer?.cancel(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 15:20:50 +08:00
										 |  |  |   void pushEvent(BaseEvent<EventType, Data> evt) { | 
					
						
							| 
									
										
										
										
											2023-03-15 10:43:27 +08:00
										 |  |  |     _evts.add(evt); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void clear() { | 
					
						
							|  |  |  |     _evts.clear(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |