From 4d60c47d3966fd809ab31ce4470f655823a389b5 Mon Sep 17 00:00:00 2001 From: Levi Date: Thu, 8 Aug 2024 18:34:00 +0800 Subject: [PATCH] feat: task detail view (#633) --- .github/workflows/build.yml | 2 +- README.md | 2 +- README_ja-JP.md | 2 +- README_vi-VN.md | 2 +- README_zh-CN.md | 2 +- README_zh-TW.md | 2 +- ui/flutter/android/app/build.gradle | 4 +- .../android/app/src/main/AndroidManifest.xml | 3 +- .../app/controllers/app_controller.dart | 24 ++-- .../modules/setting/views/setting_view.dart | 35 +++++ .../task/controllers/task_controller.dart | 5 + .../modules/task/views/task_files_view.dart | 2 +- .../lib/app/modules/task/views/task_view.dart | 121 ++++++++++++++++++ .../lib/app/views/buid_task_list_view.dart | 73 ++--------- ui/flutter/lib/app/views/copy_button.dart | 44 +++++++ ui/flutter/lib/i18n/langs/en_us.dart | 4 + ui/flutter/lib/i18n/langs/zh_cn.dart | 4 + ui/flutter/lib/i18n/langs/zh_tw.dart | 10 ++ ui/flutter/lib/util/file_explorer.dart | 14 +- ui/flutter/lib/util/log_util.dart | 8 +- ui/flutter/pubspec.lock | 20 +-- ui/flutter/pubspec.yaml | 2 +- 22 files changed, 280 insertions(+), 105 deletions(-) create mode 100644 ui/flutter/lib/app/views/copy_button.dart diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 872de07e..f93ca7a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -380,7 +380,7 @@ jobs: go install golang.org/x/mobile/cmd/gomobile@latest go get golang.org/x/mobile/bind gomobile init - gomobile bind -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile + gomobile bind -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile cd ui/flutter echo $APK_KEYSTORE | base64 -di > android/app/upload-keystore.jks flutter build apk diff --git a/README.md b/README.md index 6773c74a..4bc3f9b7 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ command: - android ```bash -gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile +gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile cd ui/flutter flutter build apk ``` diff --git a/README_ja-JP.md b/README_ja-JP.md index bd702e84..61e5bf2b 100644 --- a/README_ja-JP.md +++ b/README_ja-JP.md @@ -162,7 +162,7 @@ gomobile init - android ```bash -gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile +gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile cd ui/flutter flutter build apk ``` diff --git a/README_vi-VN.md b/README_vi-VN.md index fff9b0e0..2a5f45e6 100644 --- a/README_vi-VN.md +++ b/README_vi-VN.md @@ -170,7 +170,7 @@ command: - android ```bash -gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile +gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile cd ui/flutter flutter build apk ``` diff --git a/README_zh-CN.md b/README_zh-CN.md index 58f4bf24..90784358 100644 --- a/README_zh-CN.md +++ b/README_zh-CN.md @@ -174,7 +174,7 @@ gomobile init - android ```bash -gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile +gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile cd ui/flutter flutter build apk ``` diff --git a/README_zh-TW.md b/README_zh-TW.md index 849fc199..fd59a67b 100644 --- a/README_zh-TW.md +++ b/README_zh-TW.md @@ -170,7 +170,7 @@ gomobile init - android ```bash -gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile +gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile cd ui/flutter flutter build apk ``` diff --git a/ui/flutter/android/app/build.gradle b/ui/flutter/android/app/build.gradle index 11472895..d431b991 100644 --- a/ui/flutter/android/app/build.gradle +++ b/ui/flutter/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 + compileSdkVersion 34 ndkVersion flutter.ndkVersion compileOptions { @@ -47,7 +47,7 @@ android { applicationId "com.gopeed" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion 21 + minSdkVersion 32 targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/ui/flutter/android/app/src/main/AndroidManifest.xml b/ui/flutter/android/app/src/main/AndroidManifest.xml index c2198cf1..721bb303 100644 --- a/ui/flutter/android/app/src/main/AndroidManifest.xml +++ b/ui/flutter/android/app/src/main/AndroidManifest.xml @@ -7,7 +7,8 @@ + android:label="Gopeed" + android:extractNativeLibs="true"> { ); }); + // advanced config log items start + buildLogsDir() { + return ListTile( + title: Text("日志目录"), + subtitle: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: TextField( + controller: TextEditingController(text: logsDir()), + enabled: false, + readOnly: true, + ), + ), + Util.isDesktop() + ? IconButton( + icon: const Icon(Icons.folder_open), + onPressed: () { + launchUrl(Uri.file(logsDir())); + }, + ) + : CopyButton(logsDir()), + ], + )); + } + return Obx(() { return GestureDetector( onTap: () { @@ -953,6 +981,13 @@ class SettingView extends GetView { : null, ]), )), + const Text('开发者'), + Card( + child: Column( + children: _addDivider([ + buildLogsDir(), + ]), + )), ]), )) ], 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 62b60d5c..f5e37c9e 100644 --- a/ui/flutter/lib/app/modules/task/controllers/task_controller.dart +++ b/ui/flutter/lib/app/modules/task/controllers/task_controller.dart @@ -1,5 +1,10 @@ +import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:gopeed/api/model/task.dart'; 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/views/task_files_view.dart b/ui/flutter/lib/app/modules/task/views/task_files_view.dart index e62fc59a..0cd38d4d 100644 --- a/ui/flutter/lib/app/modules/task/views/task_files_view.dart +++ b/ui/flutter/lib/app/modules/task/views/task_files_view.dart @@ -104,7 +104,7 @@ class TaskFilesView extends GetView { }() : [ IconButton( - icon: const Icon(Icons.play_circle), + icon: const Icon(Icons.open_in_new), onPressed: () async { await OpenFilex.open(filePath); }), diff --git a/ui/flutter/lib/app/modules/task/views/task_view.dart b/ui/flutter/lib/app/modules/task/views/task_view.dart index d99f2fc9..33583291 100644 --- a/ui/flutter/lib/app/modules/task/views/task_view.dart +++ b/ui/flutter/lib/app/modules/task/views/task_view.dart @@ -1,6 +1,13 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:open_filex/open_filex.dart'; +import 'package:path/path.dart' as path; +import '../../../../api/model/task.dart'; +import '../../../../util/file_explorer.dart'; +import '../../../../util/util.dart'; +import '../../../routes/app_pages.dart'; +import '../../../views/copy_button.dart'; import '../controllers/task_controller.dart'; import '../controllers/task_downloaded_controller.dart'; import '../controllers/task_downloading_controller.dart'; @@ -12,9 +19,12 @@ class TaskView extends GetView { @override Widget build(BuildContext context) { + final selectTask = controller.selectTask; + return DefaultTabController( length: 2, child: Scaffold( + key: controller.scaffoldKey, appBar: PreferredSize( preferredSize: const Size.fromHeight(56), child: AppBar( @@ -54,7 +64,118 @@ class TaskView extends GetView { TaskDownloadedView(), ], ), + endDrawer: Drawer( + // Add a ListView to the drawer. This ensures the user can scroll + // through the options in the drawer if there isn't enough vertical + // space to fit everything. + child: Obx(() => ListView( + // Important: Remove any padding from the ListView. + padding: EdgeInsets.zero, + children: [ + SizedBox( + height: MediaQuery.of(context).padding.top + 65, + child: DrawerHeader( + child: Text( + 'taskDetail'.tr, + style: Theme.of(context).textTheme.titleLarge, + )), + ), + ListTile( + title: Text('taskName'.tr), + subtitle: + buildTooltipSubtitle(selectTask.value?.showName)), + ListTile( + title: Text('taskUrl'.tr), + subtitle: + buildTooltipSubtitle(selectTask.value?.meta.req.url), + trailing: CopyButton(selectTask.value?.meta.req.url), + ), + ListTile( + title: Text('downloadPath'.tr), + subtitle: + buildTooltipSubtitle(selectTask.value?.explorerUrl), + trailing: IconButton( + icon: const Icon(Icons.folder_open), + onPressed: () { + selectTask.value?.explorer(); + }, + ), + ), + ], + )), + ), + ), + ); + } + + Widget buildTooltipSubtitle(String? text) { + final showText = text ?? ""; + return Tooltip( + message: showText, + child: Text( + showText, + overflow: TextOverflow.ellipsis, ), ); } } + +extension TaskEnhance on Task { + String get showName { + if (meta.opts.name.isNotEmpty) { + return meta.opts.name; + } + if (meta.res == null) { + final u = Uri.parse(meta.req.url); + if (u.scheme.startsWith("http")) { + return u.path.isNotEmpty + ? u.path.substring(u.path.lastIndexOf("/") + 1) + : u.host; + } else { + final params = u.queryParameters; + if (params.containsKey("dn")) { + return params["dn"]!; + } else { + return params["xt"]!.split(":").last; + } + } + } + if (meta.res!.name.isNotEmpty) { + return meta.res!.name; + } + return meta.res!.files[0].name; + } + + bool get isFolder { + return meta.res?.name.isNotEmpty ?? false; + } + + String get explorerUrl { + if (isFolder) { + return path.join(Util.safeDir(meta.opts.path), + Util.safeDir(meta.res!.files[0].path), showName); + } else { + return path.join(Util.safeDir(meta.opts.path), Util.safeDir(showName)); + } + } + + Future explorer() async { + if (Util.isDesktop()) { + await FileExplorer.openAndSelectFile(explorerUrl); + } else { + Get.rootDelegate.toNamed(Routes.TASK_FILES, parameters: {'id': id}); + } + } + + Future open() async { + if (status != Status.done) { + return; + } + + if (isFolder) { + await explorer(); + } else { + await OpenFilex.open(explorerUrl); + } + } +} 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 c4198724..b69b79ed 100644 --- a/ui/flutter/lib/app/views/buid_task_list_view.dart +++ b/ui/flutter/lib/app/views/buid_task_list_view.dart @@ -1,18 +1,16 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:open_filex/open_filex.dart'; -import 'package:path/path.dart' as path; import 'package:styled_widget/styled_widget.dart'; import '../../api/api.dart'; -import '../../api/model/meta.dart'; import '../../api/model/task.dart'; -import '../../util/file_explorer.dart'; import '../../util/file_icon.dart'; import '../../util/icons.dart'; 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/views/task_view.dart'; import '../routes/app_pages.dart'; class BuildTaskListView extends GetView { @@ -60,17 +58,7 @@ class BuildTaskListView extends GetView { } bool isFolderTask() { - return task.meta.res?.name.isNotEmpty ?? false; - } - - String buildExplorerUrl(Task task) { - if (!isFolderTask()) { - return path.join(Util.safeDir(task.meta.opts.path), - Util.safeDir(task.meta.res!.files[0].path), fileName(task.meta)); - } else { - return path.join(Util.safeDir(task.meta.opts.path), - Util.safeDir(fileName(task.meta))); - } + return task.isFolder; } Future showDeleteDialog(String id) { @@ -119,22 +107,13 @@ class BuildTaskListView extends GetView { )); } - toTaskFilesView() { - if (Util.isDesktop()) { - FileExplorer.openAndSelectFile(buildExplorerUrl(task)); - } else { - Get.rootDelegate - .toNamed(Routes.TASK_FILES, parameters: {'id': task.id}); - } - } - List buildActions() { final list = []; if (isDone()) { list.add(IconButton( icon: const Icon(Icons.folder_open), onPressed: () { - toTaskFilesView(); + task.explorer(); }, )); } else { @@ -188,27 +167,26 @@ class BuildTaskListView extends GetView { (total > 0 ? " / ${Util.fmtByte(total)}" : ""); } + final taskController = Get.find(); + return Card( elevation: 4.0, child: InkWell( - onTap: () {}, + onTap: () { + taskController.scaffoldKey.currentState?.openEndDrawer(); + taskController.selectTask.value = task; + }, onDoubleTap: () { - if (isDone()) { - if (isFolderTask()) { - toTaskFilesView(); - } else { - OpenFilex.open(buildExplorerUrl(task)); - } - } + task.open(); }, child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( - title: Text(fileName(task.meta)), + title: Text(task.showName), leading: isFolderTask() ? const Icon(FaIcons.folder) - : Icon(FaIcons.allIcons[findIcon(fileName(task.meta))])), + : Icon(FaIcons.allIcons[findIcon(task.showName)])), Row( children: [ Expanded( @@ -239,29 +217,4 @@ class BuildTaskListView extends GetView { ), )).padding(horizontal: 14, top: 8); } - - String fileName(Meta meta) { - if (meta.opts.name.isNotEmpty) { - return meta.opts.name; - } - if (meta.res == null) { - final u = Uri.parse(meta.req.url); - if (u.scheme.startsWith("http")) { - return u.path.isNotEmpty - ? u.path.substring(u.path.lastIndexOf("/") + 1) - : u.host; - } else { - final params = u.queryParameters; - if (params.containsKey("dn")) { - return params["dn"]!; - } else { - return params["xt"]!.split(":").last; - } - } - } - if (meta.res!.name.isNotEmpty) { - return meta.res!.name; - } - return meta.res!.files[0].name; - } } diff --git a/ui/flutter/lib/app/views/copy_button.dart b/ui/flutter/lib/app/views/copy_button.dart new file mode 100644 index 00000000..5ab2f6cc --- /dev/null +++ b/ui/flutter/lib/app/views/copy_button.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../../util/message.dart'; + +class CopyButton extends StatefulWidget { + final String? url; + + const CopyButton(this.url, {Key? key}) : super(key: key); + + @override + State createState() => _CopyButtonState(); +} + +class _CopyButtonState extends State { + bool success = false; + + copy() { + final url = widget.url; + if (url != null) { + try { + Clipboard.setData(ClipboardData(text: url)); + setState(() { + success = true; + }); + Future.delayed(const Duration(milliseconds: 300), () { + setState(() { + success = false; + }); + }); + } catch (e) { + showErrorMessage(e); + } + } + } + + @override + Widget build(BuildContext context) { + return IconButton( + icon: success ? const Icon(Icons.check_circle) : const Icon(Icons.copy), + onPressed: copy, + ); + } +} diff --git a/ui/flutter/lib/i18n/langs/en_us.dart b/ui/flutter/lib/i18n/langs/en_us.dart index 1a90696a..f5bdcfea 100644 --- a/ui/flutter/lib/i18n/langs/en_us.dart +++ b/ui/flutter/lib/i18n/langs/en_us.dart @@ -99,5 +99,9 @@ const enUS = { 'seedKeep': 'Keep seeding', 'seedRatio': 'Seed ratio', 'seedTime': 'Seed time (minutes)', + 'taskDetail': 'Task Detail', + 'taskName': 'Task Name', + 'taskUrl': 'Task URL', + 'downloadPath': 'Download Path', }, }; diff --git a/ui/flutter/lib/i18n/langs/zh_cn.dart b/ui/flutter/lib/i18n/langs/zh_cn.dart index d52aae75..549637ae 100644 --- a/ui/flutter/lib/i18n/langs/zh_cn.dart +++ b/ui/flutter/lib/i18n/langs/zh_cn.dart @@ -96,5 +96,9 @@ const zhCN = { 'seedKeep': '持续做种', 'seedRatio': '做种分享率', 'seedTime': '做种时间(分钟)', + 'taskDetail': '任务详情', + 'taskName': '任务名称', + 'taskUrl': '任务链接', + 'downloadPath': '下载路径', } }; diff --git a/ui/flutter/lib/i18n/langs/zh_tw.dart b/ui/flutter/lib/i18n/langs/zh_tw.dart index 30415ed1..239cd3d1 100644 --- a/ui/flutter/lib/i18n/langs/zh_tw.dart +++ b/ui/flutter/lib/i18n/langs/zh_tw.dart @@ -96,5 +96,15 @@ const zhTW = { 'seedKeep': '持續做種', 'seedRatio': '做種分享率', 'seedTime': '做種時間(分鐘)', + /* + 'taskDetail': '任务详情', + 'taskName': '任务名称', + 'taskUrl': '任务链接', + 'downloadPath': '下载路径', + */ + 'taskDetail': '任務詳情', + 'taskName': '任務名稱', + 'taskUrl': '任務連結', + 'downloadPath': '下載路徑', } }; diff --git a/ui/flutter/lib/util/file_explorer.dart b/ui/flutter/lib/util/file_explorer.dart index e0ff2b35..060e9fd2 100644 --- a/ui/flutter/lib/util/file_explorer.dart +++ b/ui/flutter/lib/util/file_explorer.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:url_launcher/url_launcher_string.dart'; + class FileExplorer { static Future openAndSelectFile(String filePath) async { if (await FileSystemEntity.isFile(filePath)) { @@ -10,17 +12,7 @@ class FileExplorer { } static Future _openDirectory(String directoryPath) async { - if (Platform.isWindows) { - Process.run('explorer.exe', [directoryPath]); - } else if (Platform.isMacOS) { - Process.run('open', [directoryPath]); - } else if (Platform.isLinux) { - if (await _isUbuntuOrDebian()) { - Process.run('xdg-open', [directoryPath]); - } else if (await _isCentOS()) { - Process.run('nautilus', [directoryPath]); - } - } + await launchUrlString("file://$directoryPath"); } static Future _openFile(String filePath) async { diff --git a/ui/flutter/lib/util/log_util.dart b/ui/flutter/lib/util/log_util.dart index 9a1ac689..7fc51e33 100644 --- a/ui/flutter/lib/util/log_util.dart +++ b/ui/flutter/lib/util/log_util.dart @@ -15,11 +15,15 @@ initLogger() { ); } +String logsDir() { + return path.join(Util.getStorageDir(), 'logs'); +} + _buildOutput() { // if is debug mode, don't log to file if (!kDebugMode && Util.isDesktop()) { - final logDirPath = path.join(Util.getStorageDir(), 'logs'); - var logDir = Directory(logDirPath); + final logDirPath = logsDir(); + var logDir = Directory(logsDir()); if (!logDir.existsSync()) { logDir.createSync(); } diff --git a/ui/flutter/pubspec.lock b/ui/flutter/pubspec.lock index 2de159b1..bcfc4ad0 100644 --- a/ui/flutter/pubspec.lock +++ b/ui/flutter/pubspec.lock @@ -322,10 +322,10 @@ packages: dependency: "direct main" description: name: flutter_foreground_task - sha256: "6cf10a27f5e344cd2ecad0752d3a5f4ec32846d82fda8753b3fe2480ebb832a3" + sha256: "294280d8055af5628a8085bb765ba442561eaab3d5bcdf2eea4f20614f18618f" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "8.2.0" flutter_form_builder: dependency: "direct main" description: @@ -681,10 +681,10 @@ packages: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -841,10 +841,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -1054,10 +1054,10 @@ packages: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.2.4" url_launcher_linux: dependency: transitive description: @@ -1195,5 +1195,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=3.2.3 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.2.0 <4.0.0" + flutter: ">=3.16.0" diff --git a/ui/flutter/pubspec.yaml b/ui/flutter/pubspec.yaml index 05621cb7..6422a637 100644 --- a/ui/flutter/pubspec.yaml +++ b/ui/flutter/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: share_plus: ^7.1.0 flutter_form_builder: ^9.1.1 form_builder_validators: ^9.0.0 - flutter_foreground_task: ^6.1.2 + flutter_foreground_task: ^8.2.0 open_filex: ^4.3.4 tray_manager: ^0.2.3 lecle_downloads_path_provider: ^0.0.2+8