This commit is contained in:
2024-02-20 11:05:16 +08:00
parent 3ddd7041eb
commit 8f18c33a63
3 changed files with 122 additions and 9 deletions

View File

@@ -88,7 +88,9 @@ class _NewDownloadTaskPage extends State<NewDownloadTaskPage> {
Widget build(BuildContext context) {
tryInitApi(context);
if (_ok) {
context.canPop() ? context.pop() : context.go("/task_manager");
WidgetsBinding.instance!.addPostFrameCallback((_) {
context.canPop() ? context.pop() : context.go("/task_manager");
});
}
final i18n = AppLocalizations.of(context)!;
final maxWidth = MediaQuery.of(context).size.width;

View File

@@ -14,6 +14,7 @@ class TaskManager {
bool _closed = false;
bool _allowReconnect = true;
Timer? _reconnectTimer;
List<int> tasksList = [];
void clear() {
tasks.clear();
_channel?.stream.drain();
@@ -21,6 +22,29 @@ class TaskManager {
_closed = true;
}
void addToTasksList(Task task, TaskStatus status) {
if (status == TaskStatus.finished) {
tasksList.add(task.id);
return;
}
final index = tasksList.indexWhere((element) {
final otask = tasks[element];
if (otask == null) {
return false;
}
if (status == TaskStatus.wait) {
return otask.status == TaskStatus.finished;
} else {
return otask.status == TaskStatus.wait;
}
});
if (index == -1) {
tasksList.add(task.id);
} else {
tasksList.insert(index, task.id);
}
}
Future<void> connect() async {
if (auth.canManageTasks != true) return;
try {
@@ -32,36 +56,49 @@ class TaskManager {
if (type == "tasks") {
final list = TaskList.fromJson(data);
for (var task in list.tasks) {
final status = list.running.contains(task.id)
? TaskStatus.running
: TaskStatus.wait;
tasks[task.id] = TaskDetail(
base: task,
status: list.running.contains(task.id)
? TaskStatus.running
: TaskStatus.wait,
status: status,
);
addToTasksList(task, status);
}
listener.tryEmit("task_list_changed", null);
} else if (type == "new_task") {
final task = Task.fromJson(data["detail"] as Map<String, dynamic>);
tasks[task.id] = TaskDetail(
base: task,
status: TaskStatus.wait,
);
addToTasksList(task, TaskStatus.wait);
listener.tryEmit("task_list_changed", null);
} else if (type == "task_started") {
final task = Task.fromJson(data["detail"] as Map<String, dynamic>);
tasks.update(task.id, (value) {
value.status = TaskStatus.running;
tasksList.remove(task.id);
tasksList.add(task.id);
return value;
},
ifAbsent: () => TaskDetail(
base: task,
status: TaskStatus.running,
));
}, ifAbsent: () {
addToTasksList(task, TaskStatus.running);
return TaskDetail(
base: task,
status: TaskStatus.running,
);
});
listener.tryEmit("task_list_changed", null);
} else if (type == "task_finished") {
final task = Task.fromJson(data["detail"] as Map<String, dynamic>);
if (tasks.containsKey(task.id)) {
tasks.update(task.id, (value) {
value.status = TaskStatus.finished;
tasksList.remove(task.id);
tasksList.add(task.id);
return value;
});
listener.tryEmit("task_list_changed", null);
}
} else if (type == "task_progress") {
final task =
@@ -88,9 +125,16 @@ class TaskManager {
value.status = TaskStatus.failed;
value.error = info.error;
value.fataled = info.fatal;
if (info.fatal) {
tasksList.remove(info.task.id);
tasksList.add(info.task.id);
listener.tryEmit("task_list_changed", null);
}
return value;
});
}
} else if (type == "ping") {
_channel?.sink.add("{\"type\":\"pong\"}");
}
} catch (e) {
_log.warning("Error processing task message: $e");

View File

@@ -1,5 +1,7 @@
import 'dart:ui';
import 'package:enum_flag/enum_flag.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'api/task.dart';
@@ -37,6 +39,20 @@ class TaskStatusFilter {
code |= flag.value;
}
bool filter(TaskStatus status) {
if (isAll) return true;
switch (status) {
case TaskStatus.wait:
return has(TaskStatusFilterFlag.wait);
case TaskStatus.running:
return has(TaskStatusFilterFlag.running);
case TaskStatus.finished:
return has(TaskStatusFilterFlag.finished);
case TaskStatus.failed:
return has(TaskStatusFilterFlag.failed);
}
}
void remove(TaskStatusFilterFlag flag) {
code &= ~flag.value;
}
@@ -57,9 +73,59 @@ class _TaskManagerPage extends State<TaskManagerPage>
@override
void initState() {
_filter = TaskStatusFilter();
listener.on("task_list_changed", _onStateChanged);
super.initState();
}
@override
void dispose() {
listener.removeEventListener("task_list_changed", _onStateChanged);
super.dispose();
}
void _onStateChanged(dynamic _) {
setState(() {});
}
Widget _buildItem(BuildContext context, int index) {
final task = tasks.tasks[tasks.tasksList[index]];
if (task == null) {
return Container(key: ValueKey("unknown_$index"));
}
if (!_filter.filter(task.status)) {
return Container(key: ValueKey("filtered_task_${task.base.id}"));
}
return Padding(
padding: const EdgeInsets.all(8),
key: ValueKey("task_${task.base.id}"),
child: Text("TODO ${task.base.id}"));
}
Widget _proxyDecorator(Widget child, int index, Animation<double> animation) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
final double animValue = Curves.easeInOut.transform(animation.value);
final double elevation = lerpDouble(0, 6, animValue)!;
return Material(
elevation: elevation,
child: child,
);
},
child: child,
);
}
void _onReorder(int oldIndex, int newIndex) {}
Widget _buildList(BuildContext context) {
return SliverReorderableList(
itemBuilder: _buildItem,
itemCount: tasks.tasksList.length,
onReorder: _onReorder,
proxyDecorator: _proxyDecorator);
}
Widget _buildChips() {
final i18n = AppLocalizations.of(context)!;
var list = <FilterChip>[
@@ -118,6 +184,7 @@ class _TaskManagerPage extends State<TaskManagerPage>
floating: true,
),
_buildChips(),
_buildList(context),
],
);
}