remove downloadlog and use background download package

This commit is contained in:
DASHU
2025-05-08 19:05:20 +08:00
parent a55faa3f1e
commit 323037bdc6
17 changed files with 243 additions and 263 deletions

View File

@@ -11,6 +11,7 @@ mixin DeletableListMixin<T extends StatefulWidget> on State<T> {
? [
GestureDetector(
onTap: delete,
behavior: HitTestBehavior.translucent,
child: Container(
padding: const EdgeInsets.all(Base.BASE_PADDING),
child: Icon(Icons.delete_sweep_outlined),
@@ -20,20 +21,29 @@ mixin DeletableListMixin<T extends StatefulWidget> on State<T> {
: [];
}
Widget wrapListItem(Widget child,
Widget wrapListItem(Widget child, bool selected,
{required Function onTap, required Function onSelect}) {
if (deleting) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
onSelect();
},
child: child,
child: Row(
children: [
Container(
child: Checkbox(value: selected, onChanged: (bool? value) {}),
),
Expanded(child: child),
],
),
);
} else {
return GestureDetector(
onTap: () {
onTap();
},
behavior: HitTestBehavior.translucent,
onLongPress: () {
setState(() {
deleting = true;

View File

@@ -1,62 +1,72 @@
import 'package:background_downloader/background_downloader.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:nowser/const/base.dart';
import 'package:nowser/data/download_log.dart';
import 'package:nowser/main.dart';
import 'package:nowser/util/file_size_util.dart';
import 'package:path/path.dart' as path;
class DownloadListItemComponent extends StatelessWidget {
DownloadLog downloadLog;
class DownloadListItemComponent extends StatefulWidget {
// DownloadLog downloadLog;
TaskRecord taskRecord;
DownloadListItemComponent(this.downloadLog);
DownloadListItemComponent({
required this.taskRecord,
});
@override
State<StatefulWidget> createState() {
return _DownloadListItemComponent();
}
}
class _DownloadListItemComponent extends State<DownloadListItemComponent> {
@override
Widget build(BuildContext context) {
var themeData = Theme.of(context);
var taskRecord = widget.taskRecord;
Widget fileIconWidget = const Icon(
AntDesign.file1,
size: 40,
);
if (downloadLog.fileName != null) {
var mimeType = getFileType(downloadLog.fileName!);
if (mimeType.contains("image")) {
fileIconWidget = const Icon(
Icons.image,
size: 40,
);
} else if (mimeType.contains("markdown")) {
fileIconWidget = const Icon(
AntDesign.file_markdown,
size: 40,
);
} else if (mimeType.contains("document")) {
fileIconWidget = const Icon(
AntDesign.filetext1,
size: 40,
);
} else if (mimeType.contains("video")) {
fileIconWidget = const Icon(
Icons.movie,
size: 40,
);
} else if (mimeType.contains("audio")) {
fileIconWidget = const Icon(
Icons.music_note,
size: 40,
);
} else if (mimeType.contains("archive")) {
fileIconWidget = const Icon(
Icons.folder_zip,
size: 40,
);
} else if (mimeType.contains("apk")) {
fileIconWidget = const Icon(
AntDesign.android,
size: 40,
);
}
var mimeType = getFileType(widget.taskRecord.task.filename);
if (mimeType.contains("image")) {
fileIconWidget = const Icon(
Icons.image,
size: 40,
);
} else if (mimeType.contains("markdown")) {
fileIconWidget = const Icon(
AntDesign.file_markdown,
size: 40,
);
} else if (mimeType.contains("document")) {
fileIconWidget = const Icon(
AntDesign.filetext1,
size: 40,
);
} else if (mimeType.contains("video")) {
fileIconWidget = const Icon(
Icons.movie,
size: 40,
);
} else if (mimeType.contains("audio")) {
fileIconWidget = const Icon(
Icons.music_note,
size: 40,
);
} else if (mimeType.contains("archive")) {
fileIconWidget = const Icon(
Icons.folder_zip,
size: 40,
);
} else if (mimeType.contains("apk")) {
fileIconWidget = const Icon(
AntDesign.android,
size: 40,
);
}
Widget rightIcon = GestureDetector(
@@ -65,27 +75,43 @@ class DownloadListItemComponent extends StatelessWidget {
Icons.more_horiz,
),
);
if (downloadLog.progress != null) {
if (taskRecord.status == TaskStatus.running) {
rightIcon = GestureDetector(
onTap: () {},
onTap: () {
if (taskRecord.task is DownloadTask) {
downloadProvider.pauseDownload(taskRecord.task as DownloadTask);
}
},
child: const Icon(
Icons.stop_circle_outlined,
),
);
} else if (taskRecord.status == TaskStatus.paused) {
rightIcon = GestureDetector(
onTap: () {
if (taskRecord.task is DownloadTask) {
downloadProvider.resumeDownload(taskRecord.task as DownloadTask);
}
},
child: const Icon(
Icons.play_arrow,
),
);
}
// print(taskRecord.status);
Widget fileStatusWidget = Container();
if (downloadLog.progress != null) {
if (taskRecord.progress > 0 && taskRecord.progress < 1) {
fileStatusWidget = Text(
"${(downloadLog.progress! * 100).toStringAsFixed(1)}%",
"${(taskRecord.progress * 100).toStringAsFixed(1)}%",
style: TextStyle(
fontSize: themeData.textTheme.bodySmall!.fontSize,
color: themeData.hintColor,
),
);
} else if (downloadLog.fileSize != null) {
} else if (taskRecord.expectedFileSize > 0) {
fileStatusWidget = Text(
FileSizeUtil.getFileSize(downloadLog.fileSize!),
FileSizeUtil.getFileSize(taskRecord.expectedFileSize),
style: TextStyle(
fontSize: themeData.textTheme.bodySmall!.fontSize,
color: themeData.hintColor,
@@ -113,7 +139,7 @@ class DownloadListItemComponent extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
downloadLog.fileName ?? "unknow_file",
taskRecord.task.filename,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),

View File

@@ -3,10 +3,6 @@ import 'package:nowser/component/image_component.dart';
import 'package:nowser/const/base.dart';
class UrlListItemComponnet extends StatefulWidget {
bool selected;
bool selectable;
String? image;
String title;
@@ -16,8 +12,6 @@ class UrlListItemComponnet extends StatefulWidget {
int? dateTime;
UrlListItemComponnet({
this.selected = false,
this.selectable = false,
this.image,
required this.title,
required this.url,
@@ -37,14 +31,6 @@ class _UrlListItemComponnet extends State<UrlListItemComponnet> {
var smallFontSize = themeData.textTheme.bodySmall!.fontSize;
List<Widget> list = [];
if (widget.selectable) {
list.add(Container(
child: Checkbox(
value: widget.selected,
onChanged: (bool? value) {},
),
));
}
Widget iconWidget = Icon(
Icons.image,

View File

@@ -2,7 +2,7 @@ import 'package:nostr_sdk/utils/db_util.dart';
import 'package:sqflite/sqflite.dart';
class DB {
static const _VERSION = 3;
static const _VERSION = 2;
static const _dbName = "nowser.db";
@@ -41,9 +41,6 @@ class DB {
"create table bookmark(id integer not null constraint bookmark_pk primary key autoincrement,title text,url text not null,favicon text,weight integer,added_to_index integer, added_to_qa integer,created_at integer);");
db.execute(
"create table browser_history(id integer not null constraint browser_history_pk primary key autoincrement,title text,url text not null,favicon text,created_at integer);");
db.execute(
"create table download_log(id integer constraint download_log_pk primary key autoincrement,url text,file_path text,file_name TEXT,file_size integer,created_at integer);");
}
static Future<void> _onUpgrade(
@@ -52,11 +49,6 @@ class DB {
db.execute(
"alter table bookmark add added_to_qa integer after added_to_index");
}
if (oldVersion <= 2) {
db.execute(
"create table download_log(id integer constraint download_log_pk primary key autoincrement,url text,file_path text,file_name TEXT,file_size integer,created_at integer);");
}
}
static Future<Database> getCurrentDatabase() async {

View File

@@ -1,48 +0,0 @@
class DownloadLog {
int? id;
String? url;
String? filePath;
String? fileName;
int? fileSize;
int? createdAt;
String? taskId;
double? progress;
DownloadLog({
this.id,
this.url,
this.filePath,
this.fileName,
this.fileSize,
this.createdAt,
this.taskId,
this.progress,
});
DownloadLog.fromJson(Map<String, dynamic> json) {
id = json['id'];
url = json['url'];
filePath = json['file_path'];
fileName = json['file_name'];
fileSize = json['file_size'];
createdAt = json['created_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['url'] = url;
data['file_path'] = filePath;
data['file_name'] = fileName;
data['file_size'] = fileSize;
data['created_at'] = createdAt;
return data;
}
}

View File

@@ -1,34 +0,0 @@
import 'package:nowser/data/download_log.dart';
import 'package:sqflite/sqflite.dart';
import 'db.dart';
class DownloadLogDB {
static Future<int?> total({DatabaseExecutor? db}) async {
db = await DB.getDB(db);
var sql = "select count(1) from download_log";
return Sqflite.firstIntValue(await db.rawQuery(sql));
}
static Future<int> insert(DownloadLog o, {DatabaseExecutor? db}) async {
db = await DB.getDB(db);
return await db.insert("download_log", o.toJson());
}
static Future<List<DownloadLog>> all({DatabaseExecutor? db}) async {
List<DownloadLog> objs = [];
List<Object?>? arguments = [];
db = await DB.getDB(db);
var sql = "select * from download_log order by created_at desc";
List<Map<String, dynamic>> list = await db.rawQuery(sql, arguments);
for (var i = 0; i < list.length; i++) {
var json = list[i];
objs.add(DownloadLog.fromJson(json));
}
return objs;
}
static Future<void> deleteByIds(List<int> ids, {DatabaseExecutor? db}) async {
await DB.deleteByIds("download_log", ids, db: db);
}
}

View File

@@ -140,6 +140,7 @@ Future<void> doInit() async {
webProvider = WebProvider();
remoteSigningProvider = RemoteSigningProvider();
downloadProvider = DownloadProvider();
await downloadProvider.init();
}
class MyApp extends StatefulWidget {

View File

@@ -1,45 +1,41 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:nowser/data/download_log_db.dart';
import 'package:path_provider/path_provider.dart';
import 'package:background_downloader/background_downloader.dart';
import '../data/download_log.dart';
class DownloadProvider extends ChangeNotifier {
FileDownloader fileDownloader = FileDownloader();
List<DownloadLog> currentDownloadLogs = [];
List<TaskRecord> _allRecords = [];
Map<String, DownloadTask> taskMap = {};
List<TaskRecord> get allRecords => _allRecords;
// Future<void> init() async {
// await _reloadData();
// }
// Future<void> _reloadData() async {
// // _downloadLogs = await BookmarkDB.all();
// }
// Future<void> reload() async {
// await _reloadData();
// notifyListeners();
// }
void pauseDownload(String taskId) {
fileDownloader.database.allRecords();
var downloadTask = taskMap[taskId];
if (downloadTask != null) {
fileDownloader.pause(downloadTask);
}
Future<void> reloadData() async {
_allRecords = await fileDownloader.database.allRecords();
}
void resumeDownload(String taskId) {
var downloadTask = taskMap[taskId];
if (downloadTask != null) {
fileDownloader.resume(downloadTask);
}
Future<void> init() async {
await fileDownloader.start();
await reloadData();
}
Future<void> deleteTasks(List<String> taskIds) async {
await fileDownloader.database.deleteRecordsWithIds(taskIds);
await reloadData();
notifyListeners();
}
Future<void> pauseDownload(DownloadTask downloadTask) async {
fileDownloader.pause(downloadTask);
await reloadData();
notifyListeners();
}
Future<void> resumeDownload(DownloadTask downloadTask) async {
fileDownloader.resume(downloadTask);
await reloadData();
notifyListeners();
}
Future<void> startDownload(String url, String fileName) async {
@@ -60,41 +56,19 @@ class DownloadProvider extends ChangeNotifier {
allowPause: true,
);
var downloadLog = DownloadLog(
url: url,
filePath:
"$downloadDirPath${Platform.pathSeparator}downloads${Platform.pathSeparator}$fileName",
fileName: fileName,
taskId: task.taskId,
progress: 0,
);
currentDownloadLogs.add(downloadLog);
taskMap[task.taskId] = task;
// Start download, and wait for result. Show progress and status changes
// while downloading
var downloadResult = await fileDownloader.download(
task,
onProgress: (progress) {
print('Progress: ${progress * 100}%');
downloadLog.progress = progress;
notifyListeners();
},
onStatus: (status) {
print('Status: $status');
notifyListeners();
},
);
if (downloadResult.status == TaskStatus.complete) {
var file = File(downloadLog.filePath!);
downloadLog.fileSize = file.lengthSync();
downloadLog.createdAt = DateTime.now().millisecondsSinceEpoch ~/ 1000;
DownloadLogDB.insert(downloadLog);
}
currentDownloadLogs.remove(downloadLog);
await reloadData();
notifyListeners();
}
}

View File

@@ -61,8 +61,6 @@ class _BookmarkRouter extends CustState<BookmarkRouter>
var bookmark = bookmarks[index];
Widget main = UrlListItemComponnet(
selectable: deleting,
selected: selectedIds.contains(bookmark.id),
image: bookmark.favicon,
title: bookmark.title ?? "",
url: bookmark.url ?? "",
@@ -98,7 +96,8 @@ class _BookmarkRouter extends CustState<BookmarkRouter>
child: main,
);
main = wrapListItem(main, onTap: () {
main =
wrapListItem(main, selectedIds.contains(bookmark.id), onTap: () {
RouterUtil.back(context, bookmark.url);
}, onSelect: () {
if (!selectedIds.contains(bookmark.id)) {

View File

@@ -1,17 +1,17 @@
import 'package:background_downloader/background_downloader.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:nowser/component/cust_state.dart';
import 'package:nowser/component/download_list_item_component.dart';
import 'package:nowser/data/download_log.dart';
import 'package:nowser/data/download_log_db.dart';
import 'package:nowser/provider/download_provider.dart';
import 'package:nowser/main.dart';
import 'package:provider/provider.dart';
import 'package:open_file/open_file.dart';
import '../../component/appbar_back_btn_component.dart';
import '../../component/deletable_list_mixin.dart';
import '../../component/download_list_item_component.dart';
import '../../const/base.dart';
import '../../generated/l10n.dart';
import '../../util/router_util.dart';
import '../../provider/download_provider.dart';
class DownloadsRouter extends StatefulWidget {
@override
@@ -22,56 +22,55 @@ class DownloadsRouter extends StatefulWidget {
class _DownloadsRouter extends CustState<DownloadsRouter>
with DeletableListMixin {
List<int> selectedIds = [];
List<DownloadLog> completedLogs = [];
List<String> selectedIds = [];
@override
Future<void> onReady(BuildContext context) async {
var allList = await DownloadLogDB.all();
print(allList);
setState(() {
completedLogs = allList;
});
Future<void> doDelete() async {
await downloadProvider.deleteTasks(selectedIds);
selectedIds.clear();
}
@override
Future<void> onReady(BuildContext context) async {}
@override
Widget doBuild(BuildContext context) {
var themeData = Theme.of(context);
var s = S.of(context);
var _downloadProvider = Provider.of<DownloadProvider>(context);
List<DownloadLog> currentDownloadLogs =
_downloadProvider.currentDownloadLogs;
var taskRecords = _downloadProvider.allRecords;
List<Widget> list = [];
for (var logItem in currentDownloadLogs) {
list.add(wrapItem(DownloadListItemComponent(logItem), logItem));
}
int? lastMonth;
int? lastDay;
for (var logItem in completedLogs) {
if (logItem.createdAt != null) {
var date =
DateTime.fromMillisecondsSinceEpoch(logItem.createdAt! * 1000);
if (date.month != lastMonth || date.day != lastDay) {
var dateStr = DateFormat.yMd().format(date);
list.add(Container(
margin: EdgeInsets.only(
left: Base.BASE_PADDING, top: Base.BASE_PADDING),
child: Text(
dateStr,
style: TextStyle(
fontWeight: FontWeight.bold,
),
for (var taskRecord in taskRecords) {
if (taskRecord.task.creationTime.month != lastMonth ||
taskRecord.task.creationTime.day != lastDay) {
var dateStr = DateFormat.yMd().format(taskRecord.task.creationTime);
list.add(Container(
margin: const EdgeInsets.only(
left: Base.BASE_PADDING, top: Base.BASE_PADDING),
child: Text(
dateStr,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
));
}
),
));
lastMonth = taskRecord.task.creationTime.month;
lastDay = taskRecord.task.creationTime.day;
}
list.add(wrapItem(DownloadListItemComponent(logItem), logItem));
list.add(wrapItem(
DownloadListItemComponent(
taskRecord: taskRecord,
),
taskRecord,
));
}
return Scaffold(
@@ -95,17 +94,23 @@ class _DownloadsRouter extends CustState<DownloadsRouter>
);
}
Widget wrapItem(Widget child, DownloadLog downloadLog) {
return wrapListItem(child, onTap: () {
// RouterUtil.back(context, history.url);
Widget wrapItem(Widget child, TaskRecord taskRecord) {
var id = taskRecord.taskId;
return wrapListItem(child, selectedIds.contains(id), onTap: () async {
if (taskRecord.status != TaskStatus.complete) {
return;
}
var filepath = await taskRecord.task.filePath();
await OpenFile.open(filepath);
}, onSelect: () {
if (!selectedIds.contains(downloadLog.id)) {
if (!selectedIds.contains(id)) {
setState(() {
selectedIds.add(downloadLog.id!);
selectedIds.add(id);
});
} else {
setState(() {
selectedIds.remove(downloadLog.id!);
selectedIds.remove(id);
});
}
});

View File

@@ -71,15 +71,14 @@ class _HistoryRouter extends CustState<HistoryRouter> with DeletableListMixin {
}
Widget main = UrlListItemComponnet(
selectable: deleting,
selected: selectedIds.contains(history.id),
image: history.favicon,
title: history.title ?? "",
url: history.url ?? "",
dateTime: history.createdAt,
);
main = wrapListItem(main, onTap: () {
main =
wrapListItem(main, selectedIds.contains(history.id), onTap: () {
RouterUtil.back(context, history.url);
}, onSelect: () {
if (!selectedIds.contains(history.id)) {

View File

@@ -9,7 +9,6 @@ import 'package:nowser/const/router_path.dart';
import 'package:nowser/data/auth_log_db.dart';
import 'package:nowser/data/bookmark_db.dart';
import 'package:nowser/data/browser_history_db.dart';
import 'package:nowser/data/download_log_db.dart';
import 'package:nowser/main.dart';
import 'package:nowser/provider/app_provider.dart';
import 'package:nowser/provider/key_provider.dart';
@@ -54,7 +53,7 @@ class _MeRouter extends CustState<MeRouter> {
Future<void> updateNumber() async {
bookmarkNum = await BookmarkDB.total();
historyNum = await BrowserHistoryDB.total();
downloadNum = await DownloadLogDB.total();
downloadNum = downloadProvider.allRecords.length;
setState(() {});
}

View File

@@ -9,6 +9,7 @@
#include <flutter_nesigner_sdk/flutter_nesigner_sdk_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <nesigner_adapter/nesigner_adapter_plugin.h>
#include <open_file_linux/open_file_linux_plugin.h>
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
#include <window_manager/window_manager_plugin.h>
@@ -22,6 +23,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) nesigner_adapter_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "NesignerAdapterPlugin");
nesigner_adapter_plugin_register_with_registrar(nesigner_adapter_registrar);
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin");
screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar);

View File

@@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
flutter_nesigner_sdk
flutter_secure_storage_linux
nesigner_adapter
open_file_linux
screen_retriever_linux
window_manager
)

View File

@@ -11,6 +11,7 @@ import flutter_inappwebview_macos
import flutter_nesigner_sdk
import flutter_secure_storage_macos
import nesigner_adapter
import open_file_mac
import path_provider_foundation
import screen_retriever_macos
import shared_preferences_foundation
@@ -24,6 +25,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterNesignerSdkPlugin.register(with: registry.registrar(forPlugin: "FlutterNesignerSdkPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
NesignerAdapterPlugin.register(with: registry.registrar(forPlugin: "NesignerAdapterPlugin"))
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@@ -621,7 +621,7 @@ packages:
source: hosted
version: "1.15.0"
mime:
dependency: "direct main"
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
@@ -658,6 +658,70 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
open_file:
dependency: "direct main"
description:
name: open_file
sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e
url: "https://pub.dev"
source: hosted
version: "3.5.10"
open_file_android:
dependency: transitive
description:
name: open_file_android
sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa"
url: "https://pub.dev"
source: hosted
version: "1.0.6"
open_file_ios:
dependency: transitive
description:
name: open_file_ios
sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
open_file_linux:
dependency: transitive
description:
name: open_file_linux
sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550
url: "https://pub.dev"
source: hosted
version: "0.0.5"
open_file_mac:
dependency: transitive
description:
name: open_file_mac
sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
open_file_platform_interface:
dependency: transitive
description:
name: open_file_platform_interface
sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
open_file_web:
dependency: transitive
description:
name: open_file_web
sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f
url: "https://pub.dev"
source: hosted
version: "0.0.4"
open_file_windows:
dependency: transitive
description:
name: open_file_windows
sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875
url: "https://pub.dev"
source: hosted
version: "0.0.3"
path:
dependency: transitive
description:
@@ -1154,10 +1218,10 @@ packages:
dependency: transitive
description:
name: web
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:

View File

@@ -66,7 +66,7 @@ dependencies:
flutter_font_icons: ^2.2.7
path_provider: ^2.1.5
background_downloader: ^9.2.1
mime: ^2.0.0
open_file: ^3.5.10
dev_dependencies:
flutter_launcher_icons: ^0.13.1