opt: add event loop def

This commit is contained in:
Kingtous 2023-03-15 10:43:27 +08:00
parent 28ce635498
commit 6725c9544b
2 changed files with 148 additions and 8 deletions

View File

@ -4,7 +4,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/consts.dart';
import 'package:flutter_hbb/utils/event_loop.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as path;
@ -45,6 +45,7 @@ class FileModel {
late final GetSessionID getSessionID;
String get sessionID => getSessionID();
late final _FileDialogEventLoop evtLoop;
FileModel(this.parent) {
getSessionID = () => parent.target?.id ?? "";
@ -64,14 +65,17 @@ class FileModel {
jobController: jobController,
fileFetcher: fileFetcher,
getOtherSideDirectoryData: () => localController.directoryData());
evtLoop = _FileDialogEventLoop();
}
Future<void> onReady() async {
await evtLoop.onReady();
await localController.onReady();
await remoteController.onReady();
}
Future<void> close() async {
await evtLoop.close();
parent.target?.dialogManager.dismissAll();
await localController.close();
await remoteController.close();
@ -90,14 +94,16 @@ class FileModel {
fileFetcher.tryCompleteTask(evt['value'], evt['is_local']);
}
void overrideFileConfirm(Map<String, dynamic> evt) async {
final resp = await showFileConfirmDialog(
translate("Overwrite"), "${evt['read_path']}", true);
Future<void> overrideFileConfirm(Map<String, dynamic> evt,
{bool? overrideConfirm}) async {
final resp = overrideConfirm ??
await showFileConfirmDialog(
translate("Overwrite"), "${evt['read_path']}", true);
final id = int.tryParse(evt['id']) ?? 0;
if (false == resp) {
final jobIndex = jobController.getJob(id);
if (jobIndex != -1) {
jobController.cancelJob(id);
await jobController.cancelJob(id);
final job = jobController.jobTable[jobIndex];
job.state = JobState.done;
jobController.jobTable.refresh();
@ -111,7 +117,7 @@ class FileModel {
// overwrite
need_override = true;
}
bind.sessionSetConfirmOverrideFile(
await bind.sessionSetConfirmOverrideFile(
id: sessionID,
actId: id,
fileNum: int.parse(evt['file_num']),
@ -677,8 +683,8 @@ class JobController {
debugPrint("jobError $evt");
}
void cancelJob(int id) async {
bind.sessionCancelJob(id: sessionID, actId: id);
Future<void> cancelJob(int id) async {
await bind.sessionCancelJob(id: sessionID, actId: id);
}
void loadLastJob(Map<String, dynamic> evt) {
@ -1167,3 +1173,58 @@ List<Entry> _sortList(List<Entry> list, SortBy sortType, bool ascending) {
}
return [];
}
/// Define a general queue which can accepts different dialog type.
///
/// [Visibility]
/// The `_FileDialogType` and `_DialogEvent` are invisible for other models.
enum _FileDialogType { overwrite, unknown }
class _FileDialogEvent
extends BaseEvent<_FileDialogType, Map<String, dynamic>> {
WeakReference<FileModel> fileModel;
bool? _overrideConfirm;
_FileDialogEvent(this.fileModel, super.type, super.data);
void setOverrideConfirm(bool? confirm) {
_overrideConfirm = confirm;
}
@override
EventCallback<Map<String, dynamic>>? findCallback(_FileDialogType type) {
final model = fileModel.target;
if (model == null) {
return null;
}
switch (type) {
case _FileDialogType.overwrite:
return (data) async {
return await model.overrideFileConfirm(data, overrideConfirm: _overrideConfirm);
};
default:
return null;
}
}
}
class _FileDialogEventLoop extends BaseEventLoop<_FileDialogType, Map<String, dynamic>> {
bool? overrideConfirm;
@override
Future<void> onPreConsume(BaseEvent<_FileDialogType, Map<String, dynamic>> evt) async {
var event = evt as _FileDialogEvent;
event.setOverrideConfirm(overrideConfirm);
}
@override
Future<void> onEventsClear() {
overrideConfirm = null;
return super.onEventsClear();
}
void setOverrideConfirm(bool confirm) {
overrideConfirm = confirm;
}
}

View File

@ -0,0 +1,79 @@
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 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 push_event(BaseEvent<EventType, Data> evt) {
_evts.add(evt);
}
void clear() {
_evts.clear();
}
}