diff --git a/ui/flutter/lib/api/api.dart b/ui/flutter/lib/api/api.dart index a30408204..3d4d3d3ad 100644 --- a/ui/flutter/lib/api/api.dart +++ b/ui/flutter/lib/api/api.dart @@ -129,12 +129,20 @@ Future continueTask(String id) async { return _parse(() => _client.dio.put("/api/v1/tasks/$id/continue"), null); } -Future pauseAllTasks() async { - return _parse(() => _client.dio.put("/api/v1/tasks/pause"), null); +Future pauseAllTasks(List? ids) async { + return _parse( + () => _client.dio.put("/api/v1/tasks/pause", queryParameters: { + "id": ids, + }), + null); } -Future continueAllTasks() async { - return _parse(() => _client.dio.put("/api/v1/tasks/continue"), null); +Future continueAllTasks(List? ids) async { + return _parse( + () => _client.dio.put("/api/v1/tasks/continue", queryParameters: { + "id": ids, + }), + null); } Future deleteTask(String id, bool force) async { @@ -142,6 +150,15 @@ Future deleteTask(String id, bool force) async { () => _client.dio.delete("/api/v1/tasks/$id?force=$force"), null); } +Future deleteTasks(List? ids, bool force) async { + return _parse( + () => _client.dio.delete("/api/v1/tasks", queryParameters: { + "id": ids, + "force": force, + }), + null); +} + Future getConfig() async { return _parse(() => _client.dio.get("/api/v1/config"), (data) => DownloaderConfig.fromJson(data)); diff --git a/ui/flutter/lib/app/modules/app/controllers/app_controller.dart b/ui/flutter/lib/app/modules/app/controllers/app_controller.dart index f6afe3613..efec397d6 100644 --- a/ui/flutter/lib/app/modules/app/controllers/app_controller.dart +++ b/ui/flutter/lib/app/modules/app/controllers/app_controller.dart @@ -218,11 +218,11 @@ class AppController extends GetxController with WindowListener, TrayListener { ), MenuItem( label: "startAll".tr, - onClick: (menuItem) async => {continueAllTasks()}, + onClick: (menuItem) async => {continueAllTasks(null)}, ), MenuItem( label: "pauseAll".tr, - onClick: (menuItem) async => {pauseAllTasks()}, + onClick: (menuItem) async => {pauseAllTasks(null)}, ), MenuItem( label: 'setting'.tr, diff --git a/ui/flutter/lib/app/modules/task/controllers/task_controller.dart b/ui/flutter/lib/app/modules/task/controllers/task_controller.dart index f5e37c9e2..9258090f9 100644 --- a/ui/flutter/lib/app/modules/task/controllers/task_controller.dart +++ b/ui/flutter/lib/app/modules/task/controllers/task_controller.dart @@ -6,5 +6,4 @@ class TaskController extends GetxController { final tabIndex = 0.obs; final scaffoldKey = GlobalKey(); final selectTask = Rx(null); - final copyUrlDone = false.obs; } diff --git a/ui/flutter/lib/app/modules/task/controllers/task_downloading_controller.dart b/ui/flutter/lib/app/modules/task/controllers/task_downloading_controller.dart index 1f69ee0df..414b396b8 100644 --- a/ui/flutter/lib/app/modules/task/controllers/task_downloading_controller.dart +++ b/ui/flutter/lib/app/modules/task/controllers/task_downloading_controller.dart @@ -9,5 +9,13 @@ class TaskDownloadingController extends TaskListController { Status.pause, Status.wait, Status.error - ], (a, b) => b.createdAt.compareTo(a.createdAt)); + ], (a, b) { + if (a.status == Status.running && b.status != Status.running) { + return -1; + } else if (a.status != Status.running && b.status == Status.running) { + return 1; + } else { + return b.updatedAt.compareTo(a.updatedAt); + } + }); } diff --git a/ui/flutter/lib/app/modules/task/controllers/task_list_controller.dart b/ui/flutter/lib/app/modules/task/controllers/task_list_controller.dart index bca359678..19c240ee7 100644 --- a/ui/flutter/lib/app/modules/task/controllers/task_list_controller.dart +++ b/ui/flutter/lib/app/modules/task/controllers/task_list_controller.dart @@ -12,6 +12,7 @@ abstract class TaskListController extends GetxController { TaskListController(this.statuses, this.compare); final tasks = [].obs; + final selectedTaskIds = [].obs; final isRunning = false.obs; late final Timer _timer; diff --git a/ui/flutter/lib/app/modules/task/views/task_downloaded_view.dart b/ui/flutter/lib/app/modules/task/views/task_downloaded_view.dart index 331f49df5..22dcb5715 100644 --- a/ui/flutter/lib/app/modules/task/views/task_downloaded_view.dart +++ b/ui/flutter/lib/app/modules/task/views/task_downloaded_view.dart @@ -9,6 +9,7 @@ class TaskDownloadedView extends GetView { @override Widget build(BuildContext context) { - return BuildTaskListView(tasks: controller.tasks); + return BuildTaskListView( + tasks: controller.tasks, selectedTaskIds: controller.selectedTaskIds); } } diff --git a/ui/flutter/lib/app/modules/task/views/task_downloading_view.dart b/ui/flutter/lib/app/modules/task/views/task_downloading_view.dart index ae6a36d0d..dbb74a88e 100644 --- a/ui/flutter/lib/app/modules/task/views/task_downloading_view.dart +++ b/ui/flutter/lib/app/modules/task/views/task_downloading_view.dart @@ -9,6 +9,7 @@ class TaskDownloadingView extends GetView { @override Widget build(BuildContext context) { - return BuildTaskListView(tasks: controller.tasks); + return BuildTaskListView( + tasks: controller.tasks, selectedTaskIds: controller.selectedTaskIds); } } diff --git a/ui/flutter/lib/app/views/buid_task_list_view.dart b/ui/flutter/lib/app/views/buid_task_list_view.dart index 41b3ab927..6d6d1007b 100644 --- a/ui/flutter/lib/app/views/buid_task_list_view.dart +++ b/ui/flutter/lib/app/views/buid_task_list_view.dart @@ -1,3 +1,4 @@ +import 'package:contextmenu/contextmenu.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -8,16 +9,20 @@ import '../../util/message.dart'; import '../../util/util.dart'; import '../modules/app/controllers/app_controller.dart'; import '../modules/task/controllers/task_controller.dart'; +import '../modules/task/controllers/task_downloaded_controller.dart'; +import '../modules/task/controllers/task_downloading_controller.dart'; import '../modules/task/views/task_view.dart'; import '../routes/app_pages.dart'; import 'file_icon.dart'; class BuildTaskListView extends GetView { final List tasks; + final List selectedTaskIds; const BuildTaskListView({ Key? key, required this.tasks, + required this.selectedTaskIds, }) : super(key: key); @override @@ -56,11 +61,15 @@ class BuildTaskListView extends GetView { return task.status == Status.running; } + bool isSelect() { + return selectedTaskIds.contains(task.id); + } + bool isFolderTask() { return task.isFolder; } - Future showDeleteDialog(String id) { + Future showDeleteDialog(List ids) { final appController = Get.find(); final context = Get.context!; @@ -69,7 +78,8 @@ class BuildTaskListView extends GetView { context: context, barrierDismissible: false, builder: (_) => AlertDialog( - title: Text('deleteTask'.tr), + title: Text( + 'deleteTask'.trParams({'count': ids.length.toString()})), content: Obx(() => CheckboxListTile( value: appController .downloaderConfig.value.extra.lastDeleteTaskKeep, @@ -95,7 +105,7 @@ class BuildTaskListView extends GetView { final force = !appController .downloaderConfig.value.extra.lastDeleteTaskKeep; await appController.saveConfig(); - await deleteTask(id, force); + await deleteTasks(ids, force); Get.back(); } catch (e) { showErrorMessage(e); @@ -143,12 +153,35 @@ class BuildTaskListView extends GetView { list.add(IconButton( icon: const Icon(Icons.delete), onPressed: () { - showDeleteDialog(task.id); + showDeleteDialog([task.id]); }, )); 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; @@ -167,55 +200,127 @@ class BuildTaskListView extends GetView { } final taskController = Get.find(); + final taskListController = taskController.tabIndex.value == 0 + ? Get.find() + : Get.find(); - return Card( - elevation: 4.0, - child: InkWell( - onTap: () { - taskController.scaffoldKey.currentState?.openEndDrawer(); - taskController.selectTask.value = task; - }, - onDoubleTap: () { - task.open(); - }, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - title: Text(task.name), - leading: Icon( - fileIcon(task.name, - isFolder: isFolderTask(), - isBitTorrent: task.protocol == Protocol.bt), - )), - Row( + // Filter selected task ids that are still in the task list + filterSelectedTaskIds(Iterable selectedTaskIds) => selectedTaskIds + .where((id) => tasks.any((task) => task.id == id)) + .toList(); + + return ContextMenuArea( + width: 140, + builder: (context) => [ + buildContextItem(Icons.checklist, 'selectAll'.tr, () { + if (tasks.isEmpty) return; + + if (selectedTaskIds.isNotEmpty) { + taskListController.selectedTaskIds([]); + } else { + taskListController.selectedTaskIds(tasks.map((e) => e.id).toList()); + } + }), + buildContextItem(Icons.check, 'select'.tr, () { + if (isSelect()) { + taskListController.selectedTaskIds(taskListController + .selectedTaskIds + .where((element) => element != task.id) + .toList()); + } else { + taskListController.selectedTaskIds( + [...taskListController.selectedTaskIds, task.id]); + } + }), + const Divider( + indent: 8, + endIndent: 8, + ), + buildContextItem(Icons.play_arrow, 'continue'.tr, () async { + try { + await continueAllTasks(filterSelectedTaskIds( + {...taskListController.selectedTaskIds, task.id})); + } finally { + taskListController.selectedTaskIds([]); + } + }, enabled: !isDone() && !isRunning()), + buildContextItem(Icons.pause, 'pause'.tr, () async { + try { + await pauseAllTasks(filterSelectedTaskIds( + {...taskListController.selectedTaskIds, task.id})); + } finally { + taskListController.selectedTaskIds([]); + } + }, enabled: !isDone() && isRunning()), + buildContextItem(Icons.delete, 'delete'.tr, () async { + try { + await showDeleteDialog(filterSelectedTaskIds( + {...taskListController.selectedTaskIds, task.id})); + } finally { + taskListController.selectedTaskIds([]); + } + }), + ], + child: Obx( + () => Card( + elevation: 4.0, + shape: isSelect() + ? RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + side: BorderSide( + color: Theme.of(context).colorScheme.primary, + width: 2.0, + ), + ) + : null, + child: InkWell( + onTap: () { + taskController.scaffoldKey.currentState?.openEndDrawer(); + taskController.selectTask.value = task; + }, + onDoubleTap: () { + task.open(); + }, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ - Expanded( - flex: 1, - child: Text( - getProgressText(), - style: Get.textTheme.bodyLarge - ?.copyWith(color: Get.theme.disabledColor), - ).padding(left: 18)), - Expanded( - flex: 1, - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text("${Util.fmtByte(task.progress.speed)} / s", - style: Get.textTheme.titleSmall), - ...buildActions() - ], + ListTile( + title: Text(task.name), + leading: Icon( + fileIcon(task.name, + isFolder: isFolderTask(), + isBitTorrent: task.protocol == Protocol.bt), )), + Row( + children: [ + Expanded( + flex: 1, + child: Text( + getProgressText(), + style: Get.textTheme.bodyLarge + ?.copyWith(color: Get.theme.disabledColor), + ).padding(left: 18)), + Expanded( + flex: 1, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text("${Util.fmtByte(task.progress.speed)} / s", + style: Get.textTheme.titleSmall), + ...buildActions() + ], + )), + ], + ), + isDone() + ? Container() + : LinearProgressIndicator( + value: getProgress(), + ), ], ), - isDone() - ? Container() - : LinearProgressIndicator( - value: getProgress(), - ), - ], - ), - )).padding(horizontal: 14, top: 8); + )).padding(horizontal: 14, top: 8), + ), + ); } } diff --git a/ui/flutter/lib/i18n/langs/en_us.dart b/ui/flutter/lib/i18n/langs/en_us.dart index 7a2656da3..4c968cd7b 100644 --- a/ui/flutter/lib/i18n/langs/en_us.dart +++ b/ui/flutter/lib/i18n/langs/en_us.dart @@ -8,6 +8,7 @@ const enUS = { 'on': 'On', 'off': 'Off', 'selectAll': 'Select All', + 'select': 'Select', 'task': 'Tasks', 'downloading': 'downloading', 'downloaded': 'downloaded', @@ -64,9 +65,11 @@ const enUS = { 'developer': 'Developer', 'logDirectory': 'Log Directory', 'show': 'Show', + 'continue': 'Continue', + 'pause': 'Pause', 'startAll': 'Start All', 'pauseAll': 'Pause All', - 'deleteTask': 'Delete Task', + 'deleteTask': 'Delete @count tasks', 'deleteTaskTip': 'Keep downloaded files', 'delete': 'Delete', 'newVersionTitle': 'Discover new version @version', diff --git a/ui/flutter/lib/i18n/langs/es_es.dart b/ui/flutter/lib/i18n/langs/es_es.dart index 22219bc77..8fa896155 100644 --- a/ui/flutter/lib/i18n/langs/es_es.dart +++ b/ui/flutter/lib/i18n/langs/es_es.dart @@ -63,7 +63,7 @@ const esES = { 'show': 'Mostrar', 'startAll': 'Iniciar Todo', 'pauseAll': 'Pausar Todo', - 'deleteTask': 'Eliminar Tarea', + 'deleteTask': 'Eliminar @count tareas', 'deleteTaskTip': 'Mantener archivos descargados', 'delete': 'Eliminar', 'newVersionTitle': 'Nueva versión @version disponible', diff --git a/ui/flutter/lib/i18n/langs/fa_ir.dart b/ui/flutter/lib/i18n/langs/fa_ir.dart index b9825baaa..96815ef2f 100644 --- a/ui/flutter/lib/i18n/langs/fa_ir.dart +++ b/ui/flutter/lib/i18n/langs/fa_ir.dart @@ -51,7 +51,7 @@ const faIR = { 'effectAfterRestart': 'Effect after restart', 'startAll': 'شروع همه', 'pauseAll': 'توقف همه', - 'deleteTask': 'پاک کردن کار', + 'deleteTask': 'حذف @count کار', 'deleteTaskTip': 'فایل های دانلود شده را نگه دارد', 'delete': 'پاک کردن', 'newVersionTitle': '@version عنوان: کشف نسخه جدید', diff --git a/ui/flutter/lib/i18n/langs/fr_fr.dart b/ui/flutter/lib/i18n/langs/fr_fr.dart index e5e94c3da..75f630ff3 100644 --- a/ui/flutter/lib/i18n/langs/fr_fr.dart +++ b/ui/flutter/lib/i18n/langs/fr_fr.dart @@ -61,7 +61,7 @@ const frFR = { 'show': 'Afficher', 'startAll': 'Tout démarrer', 'pauseAll': 'Tout suspendre', - 'deleteTask': 'Supprimer la tâche', + 'deleteTask': 'Supprimer @count tâches', 'deleteTaskTip': 'Conserver les fichiers téléchargés', 'delete': 'Supprimer', 'newVersionTitle': 'Nouvelle version @version disponible', diff --git a/ui/flutter/lib/i18n/langs/id_id.dart b/ui/flutter/lib/i18n/langs/id_id.dart index c58a4ed19..3b11b3a06 100644 --- a/ui/flutter/lib/i18n/langs/id_id.dart +++ b/ui/flutter/lib/i18n/langs/id_id.dart @@ -67,7 +67,7 @@ const idID = { 'show': 'Tampilkan', 'startAll': 'Mulai Semua', 'pauseAll': 'Jeda Semua', - 'deleteTask': 'Hapus Tugas', + 'deleteTask': 'Hapus @count Tugas', 'deleteTaskTip': 'Simpan file yang terunduh', 'delete': 'Hapus', 'newVersionTitle': 'Temukan versi batu @version', diff --git a/ui/flutter/lib/i18n/langs/it_it.dart b/ui/flutter/lib/i18n/langs/it_it.dart index 3c53c31d6..a6e9ffb58 100644 --- a/ui/flutter/lib/i18n/langs/it_it.dart +++ b/ui/flutter/lib/i18n/langs/it_it.dart @@ -64,7 +64,7 @@ const itIT = { 'show': 'Mostra', 'startAll': 'Avvia tutti', 'pauseAll': 'Mtti in pausa tutti', - 'deleteTask': 'Elimina attività', + 'deleteTask': 'Elimina @count attività', 'deleteTaskTip': 'Conserva i file scaricati', 'delete': 'Elimina', 'newVersionTitle': 'Scopri la nuova versione @version', diff --git a/ui/flutter/lib/i18n/langs/ja_jp.dart b/ui/flutter/lib/i18n/langs/ja_jp.dart index 26bc3111a..26d999dae 100644 --- a/ui/flutter/lib/i18n/langs/ja_jp.dart +++ b/ui/flutter/lib/i18n/langs/ja_jp.dart @@ -53,7 +53,7 @@ const jaJP = { 'effectAfterRestart': '再起動後の効果', 'startAll': 'すべてを開始', 'pauseAll': 'すべてを一時停止', - 'deleteTask': 'タスクを削除', + 'deleteTask': '@count タスクを削除', 'deleteTaskTip': 'ダウンロードしたファイルを保持', 'delete': '削除', 'newVersionTitle': '新しいバージョン @version を発見する', diff --git a/ui/flutter/lib/i18n/langs/pl_pl.dart b/ui/flutter/lib/i18n/langs/pl_pl.dart index 6327da1c4..c346dde8a 100644 --- a/ui/flutter/lib/i18n/langs/pl_pl.dart +++ b/ui/flutter/lib/i18n/langs/pl_pl.dart @@ -62,7 +62,7 @@ const plPL = { 'show': 'Pokaż', 'startAll': 'Zacznij wszystkie', 'pauseAll': 'Zatrzymaj wszystkie', - 'deleteTask': 'Usuń zadanie', + 'deleteTask': 'Usuń @count zadania', 'deleteTaskTip': 'Zachowaj pobrane pliki', 'delete': 'Usuń', 'newVersionTitle': 'Sprawdź aktualizację @version', diff --git a/ui/flutter/lib/i18n/langs/ru_ru.dart b/ui/flutter/lib/i18n/langs/ru_ru.dart index e5a6f3650..eb6cd998d 100644 --- a/ui/flutter/lib/i18n/langs/ru_ru.dart +++ b/ui/flutter/lib/i18n/langs/ru_ru.dart @@ -57,7 +57,7 @@ const ruRU = { 'effectAfterRestart': 'Эффект после перезагрузки', 'startAll': 'Запустить все', 'pauseAll': 'Приостановить все', - 'deleteTask': 'Удалить задачу', + 'deleteTask': 'Удалить @count задач', 'deleteTaskTip': 'Сохранить загруженные файлы', 'delete': 'Удалить', 'newVersionTitle': 'Обнаружена новая версия @version', diff --git a/ui/flutter/lib/i18n/langs/ta_ta.dart b/ui/flutter/lib/i18n/langs/ta_ta.dart index e9e78338a..b720f9101 100644 --- a/ui/flutter/lib/i18n/langs/ta_ta.dart +++ b/ui/flutter/lib/i18n/langs/ta_ta.dart @@ -63,7 +63,7 @@ const taTA = { 'show': 'காட்டு', 'startAll': 'அனைத்தையும் தொடங்கு', 'pauseAll': 'அனைத்தையும் நிறுத்திவை', - 'deleteTask': 'பணியை நீக்கு', + 'deleteTask': 'பணிகளை நீக்கு @count', 'deleteTaskTip': 'பதிவிறக்கம் செய்யப்பட்ட கோப்புகளை வைத்திரு', 'delete': 'நீக்கு', 'newVersionTitle': 'புதிய பதிப்பைக் கண்டறியவும் @version', diff --git a/ui/flutter/lib/i18n/langs/tr_tr.dart b/ui/flutter/lib/i18n/langs/tr_tr.dart index 5c7912164..15138bbdd 100644 --- a/ui/flutter/lib/i18n/langs/tr_tr.dart +++ b/ui/flutter/lib/i18n/langs/tr_tr.dart @@ -65,7 +65,7 @@ const trTR = { 'show': 'Göster', 'startAll': 'Hepsini başlat', 'pauseAll': 'Hepsini durdur', - 'deleteTask': 'Görevleri sil', + 'deleteTask': '@count görevi sil', 'deleteTaskTip': 'İndirilen dosyaları sakla', 'delete': 'Sil', 'newVersionTitle': 'Yeni sürümü keşfet @version', diff --git a/ui/flutter/lib/i18n/langs/vi_vn.dart b/ui/flutter/lib/i18n/langs/vi_vn.dart index de182fa85..309fdf69b 100644 --- a/ui/flutter/lib/i18n/langs/vi_vn.dart +++ b/ui/flutter/lib/i18n/langs/vi_vn.dart @@ -61,7 +61,7 @@ const viVN = { 'effectAfterRestart': 'Hiệu lực sau khi khởi động lại', 'startAll': 'Bắt đầu tất cả', 'pauseAll': 'Tạm dừng tất cả', - 'deleteTask': 'Xóa nhiệm vụ', + 'deleteTask': 'Xóa @count nhiệm vụ', 'deleteTaskTip': 'Giữ các tệp đã tải về', 'delete': 'Xóa', 'newVersionTitle': 'Khám phá phiên bản mới @version', diff --git a/ui/flutter/lib/i18n/langs/zh_cn.dart b/ui/flutter/lib/i18n/langs/zh_cn.dart index b408ff145..0a8ffa661 100644 --- a/ui/flutter/lib/i18n/langs/zh_cn.dart +++ b/ui/flutter/lib/i18n/langs/zh_cn.dart @@ -8,6 +8,7 @@ const zhCN = { 'on': '开启', 'off': '关闭', 'selectAll': '全选', + 'select': '选择', 'task': '任务', 'downloading': '下载中', 'downloaded': '已完成', @@ -63,9 +64,11 @@ const zhCN = { 'developer': '开发者', 'logDirectory': '日志目录', 'show': '显示', + 'continue': '继续', + 'pause': '暂停', 'startAll': '全部开始', 'pauseAll': '全部暂停', - 'deleteTask': '删除任务', + 'deleteTask': '删除 @count 个任务', 'deleteTaskTip': '保留已下载的文件', 'delete': '删除', 'newVersionTitle': '发现新版本 @version', diff --git a/ui/flutter/lib/i18n/langs/zh_tw.dart b/ui/flutter/lib/i18n/langs/zh_tw.dart index 40f47750a..cf8bf0748 100644 --- a/ui/flutter/lib/i18n/langs/zh_tw.dart +++ b/ui/flutter/lib/i18n/langs/zh_tw.dart @@ -8,6 +8,7 @@ const zhTW = { 'on': '開啟', 'off': '關閉', 'selectAll': '全選', + 'select': '選擇', 'task': '任務', 'downloading': '下載中', 'downloaded': '已下載', @@ -63,9 +64,11 @@ const zhTW = { 'developer': '開發者', 'logDirectory': '日誌目錄', 'show': '顯示', + 'continue': '繼續', + 'pause': '暫停', 'startAll': '全部開始', 'pauseAll': '全部暫停', - 'deleteTask': '刪除任務', + 'deleteTask': '刪除 @count 個任務', 'deleteTaskTip': '保留已下載的檔案', 'delete': '刪除', 'newVersionTitle': '發現新版本 @version', diff --git a/ui/flutter/pubspec.lock b/ui/flutter/pubspec.lock index 65efd339d..7a09d9fdd 100644 --- a/ui/flutter/pubspec.lock +++ b/ui/flutter/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "64.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: @@ -17,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.2.0" + animations: + dependency: transitive + description: + name: animations + sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb + url: "https://pub.dev" + source: hosted + version: "2.0.11" app_links: dependency: "direct main" description: @@ -201,6 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + contextmenu: + dependency: "direct main" + description: + name: contextmenu + sha256: e0c7d60e2fc9f316f5b03f5fe2c0f977d65125345d1a1f77eea02be612e32d0c + url: "https://pub.dev" + source: hosted + version: "3.0.0" convert: dependency: transitive description: diff --git a/ui/flutter/pubspec.yaml b/ui/flutter/pubspec.yaml index 7d7891c59..0e2029c4f 100644 --- a/ui/flutter/pubspec.yaml +++ b/ui/flutter/pubspec.yaml @@ -69,6 +69,7 @@ dependencies: permission_handler: ^11.3.1 device_info_plus: ^9.1.2 checkable_treeview: ^1.3.1 + contextmenu: ^3.0.0 dependency_overrides: permission_handler_windows: git: