mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-08 09:30:27 +00:00
feat: implement task patching functionality (#1267)
This commit is contained in:
22 files changed
+1281
-132
No files matched your search
@@ -141,6 +141,11 @@ Future<List<String>> createTaskBatch(CreateTaskBatch createTaskBatch) async {
|
||||
(data) => (data as List).map((e) => e as String).toList());
|
||||
}
|
||||
|
||||
Future<void> patchTask(String id, ResolveTask patchTask) async {
|
||||
return _parse(
|
||||
() => _client.dio.patch("api/v1/tasks/$id", data: patchTask), null);
|
||||
}
|
||||
|
||||
Future<List<Task>> getTasks(List<Status> statuses) async {
|
||||
return _parse<List<Task>>(
|
||||
() => _client.dio.get(
|
||||
|
||||
@@ -59,6 +59,14 @@ final allTrackerSubscribeUrlCdns = {
|
||||
v: githubMirrorUrls(v, MirrorType.githubSource)
|
||||
};
|
||||
|
||||
/// Represents a task that is pending URL update via listen mode.
|
||||
class PendingUpdateTask {
|
||||
final String id;
|
||||
final String name;
|
||||
|
||||
PendingUpdateTask({required this.id, required this.name});
|
||||
}
|
||||
|
||||
class AppController extends GetxController with WindowListener, TrayListener {
|
||||
static StartConfig? _defaultStartConfig;
|
||||
|
||||
@@ -72,6 +80,10 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
final runningPort = 0.obs;
|
||||
final downloaderConfig = DownloaderConfig().obs;
|
||||
|
||||
/// The task that is pending URL update via listen mode.
|
||||
/// Stored here in AppController to persist across page navigations.
|
||||
final pendingUpdateTask = Rxn<PendingUpdateTask>();
|
||||
|
||||
late AppLinks _appLinks;
|
||||
StreamSubscription<Uri>? _linkSubscription;
|
||||
|
||||
@@ -320,7 +332,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
||||
final silent = jsonMeta['silent'] as bool? ?? false;
|
||||
final params = await ctx.readText();
|
||||
final createTaskParams = CreateTask.fromJson(_decodeParams(params));
|
||||
if (!silent) {
|
||||
if (!silent || pendingUpdateTask.value != null) {
|
||||
await windowManager.show();
|
||||
_handleToCreate0(createTaskParams);
|
||||
} else {
|
||||
|
||||
@@ -836,6 +836,26 @@ class CreateView extends GetView<CreateController> {
|
||||
: _urlController.text.trim();
|
||||
|
||||
final urls = Util.textToLines(submitUrl);
|
||||
|
||||
// Check if there is a pending update task (only for single URL)
|
||||
if (urls.length == 1) {
|
||||
final appController = Get.find<AppController>();
|
||||
final pendingTask = appController.pendingUpdateTask.value;
|
||||
if (pendingTask != null) {
|
||||
final shouldUpdate = await _showPendingUpdateDialog(
|
||||
pendingTask.id, pendingTask.name);
|
||||
if (shouldUpdate == true) {
|
||||
// Update the pending task instead of creating a new one
|
||||
await _updatePendingTask(pendingTask.id, urls.first);
|
||||
return;
|
||||
} else if (shouldUpdate == null) {
|
||||
// User cancelled, don't create task either
|
||||
return;
|
||||
}
|
||||
// shouldUpdate == false, continue to create new task
|
||||
}
|
||||
}
|
||||
|
||||
// Add url to the history
|
||||
if (!isWebFileChosen) {
|
||||
for (final url in urls) {
|
||||
@@ -890,6 +910,72 @@ class CreateView extends GetView<CreateController> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shows a dialog to ask if user wants to update pending task or create new
|
||||
/// Returns true to update, false to create new, null if cancelled
|
||||
Future<bool?> _showPendingUpdateDialog(String taskId, String taskName) async {
|
||||
return showDialog<bool>(
|
||||
context: Get.context!,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text('pendingUpdateFound'.tr),
|
||||
content: Text('pendingUpdateConfirm'.trParams({'name': taskName})),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(null),
|
||||
child: Text('cancel'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
child: Text('pendingUpdateNo'.tr),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
child: Text('pendingUpdateYes'.tr),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Updates the pending task with new URL and headers
|
||||
Future<void> _updatePendingTask(String taskId, String newUrl) async {
|
||||
try {
|
||||
// Build headers from current form
|
||||
final headers = <String, String>{};
|
||||
for (final c in _httpHeaderControllers) {
|
||||
final key = c.name.text.trim();
|
||||
final value = c.value.text.trim();
|
||||
if (key.isNotEmpty) {
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Build ReqExtraHttp
|
||||
final reqExtra = ReqExtraHttp(header: headers);
|
||||
|
||||
// Create patch request
|
||||
final patchData = ResolveTask(
|
||||
req: Request(
|
||||
url: newUrl,
|
||||
extra: reqExtra.toJson(),
|
||||
proxy: parseProxy(),
|
||||
skipVerifyCert: _skipVerifyCertController.value,
|
||||
),
|
||||
);
|
||||
|
||||
await patchTask(taskId, patchData);
|
||||
await continueTask(taskId);
|
||||
|
||||
// Clear pending update state
|
||||
final appController = Get.find<AppController>();
|
||||
appController.pendingUpdateTask.value = null;
|
||||
|
||||
Get.rootDelegate.offNamed(Routes.TASK);
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
}
|
||||
}
|
||||
|
||||
RequestProxy? parseProxy() {
|
||||
if (controller.proxyConfig.value?.mode == RequestProxyMode.custom) {
|
||||
return RequestProxy()
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:contextmenu_plus/contextmenu_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_context_menu/flutter_context_menu.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
import '../../api/api.dart';
|
||||
import '../../api/model/request.dart';
|
||||
import '../../api/model/resolve_task.dart';
|
||||
import '../../api/model/task.dart';
|
||||
import '../../util/message.dart';
|
||||
import '../../util/util.dart';
|
||||
@@ -116,6 +118,162 @@ class BuildTaskListView extends GetView {
|
||||
));
|
||||
}
|
||||
|
||||
Future<void> showUpdateUrlDialog(BuildContext context, Task task) async {
|
||||
final urlController = TextEditingController(text: task.meta.req.url);
|
||||
final headerControllers =
|
||||
<MapEntry<TextEditingController, TextEditingController>>[];
|
||||
|
||||
// Initialize with existing headers if available
|
||||
if (task.meta.req.extra != null && task.meta.req.extra is Map) {
|
||||
final extra = task.meta.req.extra as Map<String, dynamic>;
|
||||
if (extra.containsKey('header') && extra['header'] is Map) {
|
||||
final headers = extra['header'] as Map<String, dynamic>;
|
||||
for (final entry in headers.entries) {
|
||||
headerControllers.add(MapEntry(
|
||||
TextEditingController(text: entry.key),
|
||||
TextEditingController(text: entry.value.toString()),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add one empty header row by default if none exists
|
||||
if (headerControllers.isEmpty) {
|
||||
headerControllers.add(MapEntry(
|
||||
TextEditingController(),
|
||||
TextEditingController(),
|
||||
));
|
||||
}
|
||||
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: Text('updateUrl'.tr),
|
||||
content: SizedBox(
|
||||
width: 400,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TextField(
|
||||
controller: urlController,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'downloadLink'.tr,
|
||||
hintText: 'updateUrlDialogHint'.tr,
|
||||
icon: const Icon(Icons.link),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text('httpHeader'.tr,
|
||||
style: Theme.of(context).textTheme.titleMedium),
|
||||
const SizedBox(height: 8),
|
||||
...headerControllers.asMap().entries.map((entry) {
|
||||
final index = entry.key;
|
||||
final controllers = entry.value;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: controllers.key,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'httpHeaderName'.tr,
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: controllers.value,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'httpHeaderValue'.tr,
|
||||
isDense: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
headerControllers.add(MapEntry(
|
||||
TextEditingController(),
|
||||
TextEditingController(),
|
||||
));
|
||||
});
|
||||
},
|
||||
iconSize: 20,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.remove),
|
||||
onPressed: () {
|
||||
if (headerControllers.length <= 1) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
headerControllers.removeAt(index);
|
||||
});
|
||||
},
|
||||
iconSize: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text('cancel'.tr),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
TextButton(
|
||||
child: Text('confirm'.tr),
|
||||
onPressed: () async {
|
||||
try {
|
||||
// Build headers map
|
||||
final headers = <String, String>{};
|
||||
for (final entry in headerControllers) {
|
||||
final key = entry.key.text.trim();
|
||||
final value = entry.value.text.trim();
|
||||
if (key.isNotEmpty) {
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Build ReqExtraHttp
|
||||
final reqExtra = ReqExtraHttp(header: headers);
|
||||
|
||||
// Create patch request
|
||||
final patchData = ResolveTask(
|
||||
req: Request(
|
||||
url: urlController.text.trim(),
|
||||
extra: reqExtra.toJson(),
|
||||
),
|
||||
);
|
||||
|
||||
await patchTask(task.id, patchData);
|
||||
await continueTask(task.id);
|
||||
Get.back();
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> buildActions() {
|
||||
final list = <Widget>[];
|
||||
if (isDone()) {
|
||||
@@ -159,29 +317,6 @@ class BuildTaskListView extends GetView {
|
||||
return list;
|
||||
}
|
||||
|
||||
Widget buildContextItem(IconData icon, String label, Function() onTap,
|
||||
{bool enabled = true}) {
|
||||
return ListTile(
|
||||
dense: true,
|
||||
visualDensity: const VisualDensity(vertical: -1),
|
||||
minLeadingWidth: 12,
|
||||
leading: Icon(icon, size: 18),
|
||||
title: Text(label,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, // Make the text bold
|
||||
)),
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
try {
|
||||
await onTap();
|
||||
} catch (e) {
|
||||
showErrorMessage(e);
|
||||
}
|
||||
},
|
||||
enabled: enabled,
|
||||
);
|
||||
}
|
||||
|
||||
double getProgress() {
|
||||
final totalSize = task.meta.res?.size ?? 0;
|
||||
return totalSize <= 0 ? 0 : task.progress.downloaded / totalSize;
|
||||
@@ -258,6 +393,7 @@ class BuildTaskListView extends GetView {
|
||||
}
|
||||
}
|
||||
|
||||
final appController = Get.find<AppController>();
|
||||
final taskController = Get.find<TaskController>();
|
||||
final taskListController = taskController.tabIndex.value == 0
|
||||
? Get.find<TaskDownloadingController>()
|
||||
@@ -268,19 +404,24 @@ class BuildTaskListView extends GetView {
|
||||
.where((id) => tasks.any((task) => task.id == id))
|
||||
.toList();
|
||||
|
||||
return ContextMenuArea(
|
||||
width: 140,
|
||||
builder: (context) => [
|
||||
buildContextItem(Icons.checklist, 'selectAll'.tr, () {
|
||||
// Build context menu entries
|
||||
final contextMenuEntries = <ContextMenuEntry>[
|
||||
MenuItem(
|
||||
icon: const Icon(Icons.checklist),
|
||||
label: Text('selectAll'.tr),
|
||||
onSelected: (_) {
|
||||
if (tasks.isEmpty) return;
|
||||
|
||||
if (selectedTaskIds.isNotEmpty) {
|
||||
taskListController.selectedTaskIds([]);
|
||||
} else {
|
||||
taskListController.selectedTaskIds(tasks.map((e) => e.id).toList());
|
||||
}
|
||||
}),
|
||||
buildContextItem(Icons.check, 'select'.tr, () {
|
||||
},
|
||||
),
|
||||
MenuItem(
|
||||
icon: const Icon(Icons.check),
|
||||
label: Text('select'.tr),
|
||||
onSelected: (_) {
|
||||
if (isSelect()) {
|
||||
taskListController.selectedTaskIds(taskListController
|
||||
.selectedTaskIds
|
||||
@@ -290,36 +431,89 @@ class BuildTaskListView extends GetView {
|
||||
taskListController.selectedTaskIds(
|
||||
[...taskListController.selectedTaskIds, task.id]);
|
||||
}
|
||||
}),
|
||||
const Divider(
|
||||
indent: 8,
|
||||
endIndent: 8,
|
||||
),
|
||||
buildContextItem(Icons.play_arrow, 'continue'.tr, () async {
|
||||
},
|
||||
),
|
||||
const MenuDivider(),
|
||||
MenuItem(
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
label: Text('continue'.tr),
|
||||
enabled: !isDone() && !isRunning(),
|
||||
onSelected: (_) async {
|
||||
try {
|
||||
await continueAllTasks(filterSelectedTaskIds(
|
||||
{...taskListController.selectedTaskIds, task.id}));
|
||||
} finally {
|
||||
taskListController.selectedTaskIds([]);
|
||||
}
|
||||
}, enabled: !isDone() && !isRunning()),
|
||||
buildContextItem(Icons.pause, 'pause'.tr, () async {
|
||||
},
|
||||
),
|
||||
MenuItem(
|
||||
icon: const Icon(Icons.pause),
|
||||
label: Text('pause'.tr),
|
||||
enabled: !isDone() && isRunning(),
|
||||
onSelected: (_) async {
|
||||
try {
|
||||
await pauseAllTasks(filterSelectedTaskIds(
|
||||
{...taskListController.selectedTaskIds, task.id}));
|
||||
} finally {
|
||||
taskListController.selectedTaskIds([]);
|
||||
}
|
||||
}, enabled: !isDone() && isRunning()),
|
||||
buildContextItem(Icons.delete, 'delete'.tr, () async {
|
||||
},
|
||||
),
|
||||
MenuItem(
|
||||
icon: const Icon(Icons.delete),
|
||||
label: Text('delete'.tr),
|
||||
onSelected: (_) async {
|
||||
try {
|
||||
await showDeleteDialog(filterSelectedTaskIds(
|
||||
{...taskListController.selectedTaskIds, task.id}));
|
||||
} finally {
|
||||
taskListController.selectedTaskIds([]);
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
),
|
||||
// Update URL submenu - only enabled for HTTP tasks in pause or error status
|
||||
const MenuDivider(),
|
||||
MenuItem.submenu(
|
||||
icon: const Icon(Icons.link),
|
||||
label: Text('updateUrl'.tr),
|
||||
enabled: task.protocol == Protocol.http &&
|
||||
(task.status == Status.pause || task.status == Status.error),
|
||||
items: [
|
||||
MenuItem(
|
||||
icon: const Icon(Icons.edit_note),
|
||||
label: Text('updateUrlManual'.tr),
|
||||
onSelected: (_) async {
|
||||
await showUpdateUrlDialog(context, task);
|
||||
},
|
||||
),
|
||||
MenuItem(
|
||||
icon: Icon(appController.pendingUpdateTask.value?.id == task.id
|
||||
? Icons.cancel
|
||||
: Icons.sensors),
|
||||
label: Text(appController.pendingUpdateTask.value?.id == task.id
|
||||
? 'updateUrlCancelListen'.tr
|
||||
: 'updateUrlListen'.tr),
|
||||
onSelected: (_) {
|
||||
if (appController.pendingUpdateTask.value?.id == task.id) {
|
||||
appController.pendingUpdateTask.value = null;
|
||||
} else {
|
||||
appController.pendingUpdateTask.value =
|
||||
PendingUpdateTask(id: task.id, name: task.name);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
final contextMenu = ContextMenu(
|
||||
entries: contextMenuEntries,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
);
|
||||
|
||||
return ContextMenuRegion(
|
||||
contextMenu: contextMenu,
|
||||
child: Obx(
|
||||
() => Card(
|
||||
elevation: 4.0,
|
||||
@@ -344,7 +538,24 @@ class BuildTaskListView extends GetView {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text(task.name),
|
||||
title: Row(
|
||||
children: [
|
||||
Expanded(child: Text(task.name)),
|
||||
// Show pending update indicator
|
||||
if (appController.pendingUpdateTask.value?.id ==
|
||||
task.id)
|
||||
Tooltip(
|
||||
message: 'updateUrlListeningTip'.tr,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8),
|
||||
child: Icon(Icons.hearing,
|
||||
size: 16,
|
||||
color:
|
||||
Theme.of(context).colorScheme.primary),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
leading: Icon(
|
||||
fileIcon(task.name,
|
||||
isFolder: isFolderTask(),
|
||||
|
||||
@@ -147,6 +147,7 @@ const enUS = {
|
||||
'unknown': 'Unknown',
|
||||
'fileSelectedCount': 'Files: ',
|
||||
'fileSelectedSize': 'Size: ',
|
||||
'httpHeader': 'Header',
|
||||
'httpHeaderName': 'Header Name',
|
||||
'httpHeaderValue': 'Header Value',
|
||||
'login': 'Login',
|
||||
@@ -177,5 +178,16 @@ const enUS = {
|
||||
'githubMirrorType': 'Mirror Type',
|
||||
'githubMirrorUrl': 'Mirror URL',
|
||||
'githubMirrorUrlHint': 'Enter mirror URL',
|
||||
'updateUrl': 'Update URL',
|
||||
'updateUrlManual': 'Manual Update',
|
||||
'updateUrlListen': 'Listen Update',
|
||||
'updateUrlListeningTip': 'Waiting for URL update',
|
||||
'updateUrlCancelListen': 'Cancel Listen',
|
||||
'updateUrlDialogHint': 'Enter new download URL',
|
||||
'pendingUpdateFound': 'Pending Update Task Found',
|
||||
'pendingUpdateConfirm':
|
||||
'Task "@name" is waiting for URL update. Do you want to update it with the new URL?',
|
||||
'pendingUpdateYes': 'Update Task',
|
||||
'pendingUpdateNo': 'Create New Task',
|
||||
},
|
||||
};
|
||||
@@ -144,6 +144,7 @@ const zhCN = {
|
||||
'unknown': '未知',
|
||||
'fileSelectedCount': '文件数:',
|
||||
'fileSelectedSize': '大小:',
|
||||
'httpHeader': '请求头',
|
||||
'httpHeaderName': '请求头名称',
|
||||
'httpHeaderValue': '请求头值',
|
||||
'login': '登录',
|
||||
@@ -173,5 +174,15 @@ const zhCN = {
|
||||
'githubMirrorType': '镜像类型',
|
||||
'githubMirrorUrl': '镜像地址',
|
||||
'githubMirrorUrlHint': '请输入镜像地址',
|
||||
'updateUrl': '更新地址',
|
||||
'updateUrlManual': '手动更新',
|
||||
'updateUrlListen': '监听更新',
|
||||
'updateUrlListeningTip': '正在等待更新地址',
|
||||
'updateUrlCancelListen': '取消监听',
|
||||
'updateUrlDialogHint': '请输入新的下载地址',
|
||||
'pendingUpdateFound': '发现待更新任务',
|
||||
'pendingUpdateConfirm': '任务 "@name" 正在等待更新地址,是否使用新地址更新该任务?',
|
||||
'pendingUpdateYes': '更新任务',
|
||||
'pendingUpdateNo': '创建新任务',
|
||||
}
|
||||
};
|
||||
+8
-64
@@ -9,14 +9,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "67.0.0"
|
||||
after_layout:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: after_layout
|
||||
sha256: "95a1cb2ca1464f44f14769329fbf15987d20ab6c88f8fc5d359bd362be625f29"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -25,14 +17,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.4.1"
|
||||
animations:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: animations
|
||||
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
app_links:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -233,22 +217,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
context_menus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: context_menus
|
||||
sha256: "3b4f846a7a7dcb8cc76bb0c8c1b3915501f5f7370c524e3aa00ab4cc048f08db"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
contextmenu_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: contextmenu_plus
|
||||
sha256: c4c3a11633ba98b6e325e80942cd6ca29269b246e307b0a43514ae4f9c8bcc7f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -393,19 +361,19 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
fluent_ui:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fluent_ui
|
||||
sha256: e7804bf3bbb3ecf9e77d5498181dc36375f5ca736ccfb3862fea17c50050eb89
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.2"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_context_menu:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_context_menu
|
||||
sha256: e8f2cd13ef5e3320e35b27b3f7de278d9fc6b3f9c328cc16cd90784fb66d1054
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.1"
|
||||
flutter_foreground_task:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -734,14 +702,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
math_expressions:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: math_expressions
|
||||
sha256: e32d803d758ace61cc6c4bdfed1226ff60a6a23646b35685670d28b5616139f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.0"
|
||||
menu_base:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1007,14 +967,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.2"
|
||||
recase:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: recase
|
||||
sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
rounded_loading_button_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1039,14 +991,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.9"
|
||||
scroll_pos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: scroll_pos
|
||||
sha256: cebf602b2dd939de6832bb902ffefb574608d1b84f420b82b381a4007d3c1e1b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
share_handler:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -37,7 +37,7 @@ dependencies:
|
||||
cupertino_icons: ^1.0.2
|
||||
get: ^4.6.6
|
||||
styled_widget: ^0.4.0+3
|
||||
context_menus: ^1.2.0
|
||||
flutter_context_menu: ^0.4.1
|
||||
json_annotation: ^4.8.1
|
||||
dio: ^5.2.1
|
||||
path_provider: ^2.1.4
|
||||
@@ -47,7 +47,6 @@ dependencies:
|
||||
logger: ^1.4.0
|
||||
desktop_drop: ^0.4.4
|
||||
package_info_plus: ^8.1.0
|
||||
fluent_ui: ^4.9.2
|
||||
path: ^1.9.0
|
||||
badges: ^3.0.3
|
||||
app_links: ^6.3.3
|
||||
@@ -72,7 +71,6 @@ dependencies:
|
||||
permission_handler: ^11.3.1
|
||||
device_info_plus: ^11.1.0
|
||||
checkable_treeview: ^1.3.1
|
||||
contextmenu_plus: ^1.0.1
|
||||
contentsize_tabbarview: ^0.0.2
|
||||
win32_registry: ^1.1.5
|
||||
share_handler: ^0.0.22
|
||||
|
||||
Reference in new issue
Block a user