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; /// Constructor. BaseEvent(this.type, this.data); /// Consume this event. @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; // Handle the logic. await onEventsStartConsuming(); while (_evts.isNotEmpty) { final evt = _evts.first; _evts.remove(evt); await onPreConsume(evt); await evt.consume(); await onPostConsume(evt); } await onEventsClear(); // Now events are all processed. _timer = Timer.periodic(Duration(milliseconds: 100), _handleTimer); } Future<void> close() async { _timer?.cancel(); } void pushEvent(BaseEvent<EventType, Data> evt) { _evts.add(evt); } void clear() { _evts.clear(); } }