opt: add event loop def
This commit is contained in:
parent
28ce635498
commit
6725c9544b
@ -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;
|
||||
}
|
||||
}
|
79
flutter/lib/utils/event_loop.dart
Normal file
79
flutter/lib/utils/event_loop.dart
Normal 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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user