mirror of
https://github.com/haorendashu/nowser.git
synced 2025-12-17 09:54:19 +01:00
download some codes
This commit is contained in:
182
lib/component/download_list_item_component.dart
Normal file
182
lib/component/download_list_item_component.dart
Normal file
@@ -0,0 +1,182 @@
|
||||
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;
|
||||
|
||||
DownloadListItemComponent(this.downloadLog);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var themeData = Theme.of(context);
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget rightIcon = GestureDetector(
|
||||
onTap: () {},
|
||||
child: const Icon(
|
||||
Icons.more_horiz,
|
||||
),
|
||||
);
|
||||
if (downloadLog.progress != null) {
|
||||
rightIcon = GestureDetector(
|
||||
onTap: () {},
|
||||
child: const Icon(
|
||||
Icons.stop_circle_outlined,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget fileStatusWidget = Container();
|
||||
if (downloadLog.progress != null) {
|
||||
fileStatusWidget = Text(
|
||||
"${(downloadLog.progress! * 100).toStringAsFixed(1)}%",
|
||||
style: TextStyle(
|
||||
fontSize: themeData.textTheme.bodySmall!.fontSize,
|
||||
color: themeData.hintColor,
|
||||
),
|
||||
);
|
||||
} else if (downloadLog.fileSize != null) {
|
||||
fileStatusWidget = Text(
|
||||
FileSizeUtil.getFileSize(downloadLog.fileSize!),
|
||||
style: TextStyle(
|
||||
fontSize: themeData.textTheme.bodySmall!.fontSize,
|
||||
color: themeData.hintColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(
|
||||
left: Base.BASE_PADDING_HALF,
|
||||
right: Base.BASE_PADDING_HALF,
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: fileIconWidget,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
downloadLog.fileName ?? "unknow_file",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
fileStatusWidget,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
child: rightIcon,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String getFileType(String filePath) {
|
||||
// 获取扩展名(含点,如 '.jpg')
|
||||
String extension = path.extension(filePath).toLowerCase();
|
||||
|
||||
// 处理无扩展名的情况
|
||||
if (extension.isEmpty) return 'other';
|
||||
|
||||
// 去掉点并检查映射
|
||||
String cleanedExtension =
|
||||
extension.startsWith('.') ? extension.substring(1) : extension;
|
||||
|
||||
return _fileExtensionToType[cleanedExtension] ?? 'other';
|
||||
}
|
||||
|
||||
Map<String, String> _fileExtensionToType = {
|
||||
// 图片类型
|
||||
'jpg': 'image',
|
||||
'jpeg': 'image',
|
||||
'png': 'image',
|
||||
'gif': 'image',
|
||||
'webp': 'image',
|
||||
'bmp': 'image',
|
||||
'mp4': 'video',
|
||||
'mov': 'video',
|
||||
'avi': 'video',
|
||||
'mkv': 'video',
|
||||
'flv': 'video',
|
||||
'pdf': 'document',
|
||||
'doc': 'document',
|
||||
'docx': 'document',
|
||||
'xls': 'document',
|
||||
'xlsx': 'document',
|
||||
'ppt': 'document',
|
||||
'pptx': 'document',
|
||||
'txt': 'document',
|
||||
'md': 'markdown',
|
||||
'markdown': 'markdown',
|
||||
'mp3': 'audio',
|
||||
'wav': 'audio',
|
||||
'aac': 'audio',
|
||||
'ogg': 'audio',
|
||||
'zip': 'archive',
|
||||
'rar': 'archive',
|
||||
'7z': 'archive',
|
||||
'tar': 'archive',
|
||||
'gz': 'archive',
|
||||
'apk': 'apk',
|
||||
};
|
||||
}
|
||||
121
lib/component/download_task_dialog.dart
Normal file
121
lib/component/download_task_dialog.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:nostr_sdk/utils/platform_util.dart';
|
||||
import 'package:nowser/provider/download_provider.dart';
|
||||
import 'package:nowser/util/router_util.dart';
|
||||
|
||||
import '../const/base.dart';
|
||||
import '../generated/l10n.dart';
|
||||
import '../main.dart';
|
||||
import '../util/table_mode_util.dart';
|
||||
|
||||
class DownloadTaskDialog extends StatefulWidget {
|
||||
String downloadUrl;
|
||||
|
||||
DownloadTaskDialog(this.downloadUrl);
|
||||
|
||||
static Future<void> show(BuildContext context, String downloadUrl) async {
|
||||
await showDialog<String>(
|
||||
context: context,
|
||||
builder: (_context) {
|
||||
return DownloadTaskDialog(downloadUrl);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _DownloadTaskDialog();
|
||||
}
|
||||
}
|
||||
|
||||
class _DownloadTaskDialog extends State<DownloadTaskDialog> {
|
||||
TextEditingController urlTextController = TextEditingController();
|
||||
|
||||
TextEditingController fileNameTextController = TextEditingController();
|
||||
|
||||
late S s;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
String fileName =
|
||||
widget.downloadUrl.substring(widget.downloadUrl.lastIndexOf('/') + 1);
|
||||
|
||||
urlTextController.text = widget.downloadUrl;
|
||||
fileNameTextController.text = fileName;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var themeData = Theme.of(context);
|
||||
s = S.of(context);
|
||||
|
||||
List<Widget> list = [];
|
||||
list.add(Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: Base.BASE_PADDING,
|
||||
),
|
||||
child: Text(
|
||||
s.Downloads,
|
||||
style: TextStyle(
|
||||
fontSize: themeData.textTheme.bodyLarge!.fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
list.add(Container(
|
||||
child: TextField(
|
||||
controller: urlTextController,
|
||||
decoration: InputDecoration(
|
||||
labelText: s.Url,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
list.add(Container(
|
||||
child: TextField(
|
||||
controller: fileNameTextController,
|
||||
decoration: InputDecoration(
|
||||
labelText: s.Name,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
list.add(Container(
|
||||
margin: EdgeInsets.only(
|
||||
top: Base.BASE_PADDING * 2,
|
||||
bottom: Base.BASE_PADDING,
|
||||
),
|
||||
width: double.infinity,
|
||||
child: FilledButton(onPressed: confirm, child: Text(s.Confirm)),
|
||||
));
|
||||
|
||||
Widget main = Container(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: list,
|
||||
),
|
||||
);
|
||||
if (PlatformUtil.isPC() || TableModeUtil.isTableMode()) {
|
||||
main = Container(
|
||||
width: mediaDataCache.size.width / 2,
|
||||
child: main,
|
||||
);
|
||||
}
|
||||
|
||||
return Dialog(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(Base.BASE_PADDING * 2),
|
||||
child: main,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void confirm() {
|
||||
var url = urlTextController.text;
|
||||
var fileName = fileNameTextController.text;
|
||||
downloadProvider.startDownload(url, fileName);
|
||||
RouterUtil.back(context);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:nostr_sdk/utils/string_util.dart';
|
||||
import 'package:nowser/component/download_task_dialog.dart';
|
||||
import 'package:nowser/main.dart';
|
||||
|
||||
import '../../const/base.dart';
|
||||
@@ -98,7 +99,9 @@ class _LongPressDialog extends State<LongPressDialog> {
|
||||
));
|
||||
list.add(LongPressDialogItem(
|
||||
s.Download_image,
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
DownloadTaskDialog.show(context, src);
|
||||
},
|
||||
showBottomLine: false,
|
||||
));
|
||||
}
|
||||
@@ -180,10 +183,10 @@ class LongPressDialogItem extends StatelessWidget {
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
RouterUtil.back(context);
|
||||
if (onTap != null) {
|
||||
onTap!();
|
||||
}
|
||||
RouterUtil.back(context);
|
||||
},
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:nostr_sdk/event.dart';
|
||||
import 'package:nostr_sdk/utils/platform_util.dart';
|
||||
import 'package:nostr_sdk/utils/string_util.dart';
|
||||
import 'package:nowser/component/download_task_dialog.dart';
|
||||
import 'package:nowser/component/webview/long_press_dialog.dart';
|
||||
import 'package:nowser/component/webview/web_info.dart';
|
||||
import 'package:nowser/const/app_type.dart';
|
||||
@@ -224,6 +225,11 @@ class _WebViewComponent extends State<WebViewComponent>
|
||||
}
|
||||
}
|
||||
},
|
||||
onDownloadStartRequest: (InAppWebViewController controller,
|
||||
DownloadStartRequest downloadStartRequest) {
|
||||
String downloadUrl = downloadStartRequest.url.path;
|
||||
DownloadTaskDialog.show(context, downloadUrl);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,4 +12,5 @@ class RouterPath {
|
||||
static const String AUTH_LOGS = "/authLogs";
|
||||
static const String SETTING = "/setting";
|
||||
static const String ABOUT_ME = "/aboutMe";
|
||||
static const String DOWNLOADS = "/downloads";
|
||||
}
|
||||
|
||||
@@ -29,14 +29,18 @@ class BrowserHistoryDB {
|
||||
}
|
||||
|
||||
static Future<void> deleteByIds(List<int> ids, {DatabaseExecutor? db}) async {
|
||||
var sql = "delete from browser_history where id in(";
|
||||
for (var id in ids) {
|
||||
sql += "?,";
|
||||
await DB.deleteByIds("browser_history", ids, db: db);
|
||||
}
|
||||
sql = sql.substring(0, sql.length - 1);
|
||||
sql += ")";
|
||||
|
||||
db = await DB.getDB(db);
|
||||
await db.execute(sql, ids);
|
||||
}
|
||||
// static Future<void> deleteByIds(List<int> ids, {DatabaseExecutor? db}) async {
|
||||
// var sql = "delete from browser_history where id in(";
|
||||
// for (var id in ids) {
|
||||
// sql += "?,";
|
||||
// }
|
||||
// sql = sql.substring(0, sql.length - 1);
|
||||
// sql += ")";
|
||||
|
||||
// db = await DB.getDB(db);
|
||||
// await db.execute(sql, ids);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:nostr_sdk/utils/db_util.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class DB {
|
||||
static const _VERSION = 2;
|
||||
static const _VERSION = 3;
|
||||
|
||||
static const _dbName = "nowser.db";
|
||||
|
||||
@@ -41,14 +41,22 @@ 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(
|
||||
Database db, int oldVersion, int newVersion) async {
|
||||
if (oldVersion == 1 && newVersion == 2) {
|
||||
if (oldVersion == 1) {
|
||||
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 {
|
||||
@@ -69,4 +77,17 @@ class DB {
|
||||
_database?.close();
|
||||
_database = null;
|
||||
}
|
||||
|
||||
static Future<void> deleteByIds(String tableName, List<int> ids,
|
||||
{DatabaseExecutor? db}) async {
|
||||
var sql = "delete from $tableName where id in(";
|
||||
for (var id in ids) {
|
||||
sql += "?,";
|
||||
}
|
||||
sql = sql.substring(0, sql.length - 1);
|
||||
sql += ")";
|
||||
|
||||
db = await DB.getDB(db);
|
||||
await db.execute(sql, ids);
|
||||
}
|
||||
}
|
||||
|
||||
48
lib/data/download_log.dart
Normal file
48
lib/data/download_log.dart
Normal file
@@ -0,0 +1,48 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
34
lib/data/download_log_db.dart
Normal file
34
lib/data/download_log_db.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import 'package:nowser/provider/android_signer_mixin.dart';
|
||||
import 'package:nowser/provider/app_provider.dart';
|
||||
import 'package:nowser/provider/bookmark_provider.dart';
|
||||
import 'package:nowser/provider/build_in_relay_provider.dart';
|
||||
import 'package:nowser/provider/download_provider.dart';
|
||||
import 'package:nowser/provider/key_provider.dart';
|
||||
import 'package:nowser/provider/permission_check_mixin.dart';
|
||||
import 'package:nowser/provider/web_provider.dart';
|
||||
@@ -24,6 +25,7 @@ import 'package:nowser/router/apps/add_remote_app_router.dart';
|
||||
import 'package:nowser/router/apps/apps_router.dart';
|
||||
import 'package:nowser/router/auth_log/auth_logs_router.dart';
|
||||
import 'package:nowser/router/bookmark/bookmark_router.dart';
|
||||
import 'package:nowser/router/downloads/downloads_router.dart';
|
||||
import 'package:nowser/router/history/history_router.dart';
|
||||
import 'package:nowser/router/index/index_router.dart';
|
||||
import 'package:nowser/router/keys/keys_router.dart';
|
||||
@@ -65,6 +67,8 @@ late RootIsolateToken rootIsolateToken;
|
||||
|
||||
late BuildInRelayProvider buildInRelayProvider;
|
||||
|
||||
late DownloadProvider downloadProvider;
|
||||
|
||||
const QuickActions quickActions = QuickActions();
|
||||
|
||||
BookmarkProvider bookmarkProvider = BookmarkProvider();
|
||||
@@ -135,6 +139,7 @@ Future<void> doInit() async {
|
||||
settingProvider = futureResultList[0] as SettingProvider;
|
||||
webProvider = WebProvider();
|
||||
remoteSigningProvider = RemoteSigningProvider();
|
||||
downloadProvider = DownloadProvider();
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
@@ -197,6 +202,7 @@ class _MyApp extends State<MyApp> {
|
||||
RouterPath.AUTH_LOGS: (context) => AuthLogsRouter(),
|
||||
RouterPath.SETTING: (context) => SettingRouter(indexReload: reload),
|
||||
RouterPath.ABOUT_ME: (context) => AboutMeRouter(),
|
||||
RouterPath.DOWNLOADS: (context) => DownloadsRouter(),
|
||||
};
|
||||
|
||||
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||
@@ -229,6 +235,9 @@ class _MyApp extends State<MyApp> {
|
||||
ListenableProvider<BookmarkProvider>.value(
|
||||
value: bookmarkProvider,
|
||||
),
|
||||
ListenableProvider<DownloadProvider>.value(
|
||||
value: downloadProvider,
|
||||
),
|
||||
],
|
||||
child: MaterialApp(
|
||||
builder: BotToastInit(),
|
||||
|
||||
100
lib/provider/download_provider.dart
Normal file
100
lib/provider/download_provider.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
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 = [];
|
||||
|
||||
Map<String, DownloadTask> taskMap = {};
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
void resumeDownload(String taskId) {
|
||||
var downloadTask = taskMap[taskId];
|
||||
if (downloadTask != null) {
|
||||
fileDownloader.resume(downloadTask);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> startDownload(String url, String fileName) async {
|
||||
var downloadDir = await getApplicationDocumentsDirectory();
|
||||
|
||||
var downloadDirPath = downloadDir.absolute.path;
|
||||
|
||||
print("url $url fileName $fileName downloadDirPath $downloadDirPath");
|
||||
|
||||
final task = DownloadTask(
|
||||
url: url,
|
||||
filename: fileName,
|
||||
baseDirectory: BaseDirectory.applicationDocuments,
|
||||
directory: 'downloads',
|
||||
updates: Updates.statusAndProgress, // request status and progress updates
|
||||
requiresWiFi: false,
|
||||
retries: 5,
|
||||
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');
|
||||
},
|
||||
);
|
||||
|
||||
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);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,10 @@ class _BookmarkRouter extends CustState<BookmarkRouter>
|
||||
setState(() {
|
||||
selectedIds.add(bookmark.id!);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
selectedIds.remove(bookmark.id!);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
113
lib/router/downloads/downloads_router.dart
Normal file
113
lib/router/downloads/downloads_router.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
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:provider/provider.dart';
|
||||
|
||||
import '../../component/appbar_back_btn_component.dart';
|
||||
import '../../component/deletable_list_mixin.dart';
|
||||
import '../../const/base.dart';
|
||||
import '../../generated/l10n.dart';
|
||||
import '../../util/router_util.dart';
|
||||
|
||||
class DownloadsRouter extends StatefulWidget {
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _DownloadsRouter();
|
||||
}
|
||||
}
|
||||
|
||||
class _DownloadsRouter extends CustState<DownloadsRouter>
|
||||
with DeletableListMixin {
|
||||
List<int> selectedIds = [];
|
||||
|
||||
List<DownloadLog> completedLogs = [];
|
||||
|
||||
@override
|
||||
Future<void> onReady(BuildContext context) async {
|
||||
var allList = await DownloadLogDB.all();
|
||||
print(allList);
|
||||
setState(() {
|
||||
completedLogs = allList;
|
||||
});
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
list.add(wrapItem(DownloadListItemComponent(logItem), logItem));
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: AppbarBackBtnComponent(),
|
||||
title: Text(
|
||||
s.Downloads,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: themeData.textTheme.bodyLarge!.fontSize,
|
||||
),
|
||||
),
|
||||
actions: genAppBarActions(context),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: list,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget wrapItem(Widget child, DownloadLog downloadLog) {
|
||||
return wrapListItem(child, onTap: () {
|
||||
// RouterUtil.back(context, history.url);
|
||||
}, onSelect: () {
|
||||
if (!selectedIds.contains(downloadLog.id)) {
|
||||
setState(() {
|
||||
selectedIds.add(downloadLog.id!);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
selectedIds.remove(downloadLog.id!);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,10 @@ class _HistoryRouter extends CustState<HistoryRouter> with DeletableListMixin {
|
||||
setState(() {
|
||||
selectedIds.add(history.id!);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
selectedIds.remove(history.id!);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class _WebControlComponent extends State<WebControlComponent> {
|
||||
size: 30,
|
||||
),
|
||||
onTap: () {
|
||||
BotToast.showText(text: s.Comming_soon);
|
||||
RouterUtil.router(context, RouterPath.DOWNLOADS);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -9,6 +9,7 @@ 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';
|
||||
@@ -53,6 +54,7 @@ class _MeRouter extends CustState<MeRouter> {
|
||||
Future<void> updateNumber() async {
|
||||
bookmarkNum = await BookmarkDB.total();
|
||||
historyNum = await BrowserHistoryDB.total();
|
||||
downloadNum = await DownloadLogDB.total();
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@@ -186,7 +188,7 @@ class _MeRouter extends CustState<MeRouter> {
|
||||
name: s.Downloads,
|
||||
iconData: Icons.download,
|
||||
onTap: () {
|
||||
BotToast.showText(text: s.Comming_soon);
|
||||
RouterUtil.router(context, RouterPath.DOWNLOADS);
|
||||
},
|
||||
));
|
||||
// webItemList.add(MeRouterWebItemComponent(
|
||||
|
||||
12
lib/util/file_size_util.dart
Normal file
12
lib/util/file_size_util.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
class FileSizeUtil {
|
||||
static String getFileSize(int fileSize) {
|
||||
if (fileSize > 1024 * 1024 * 1024) {
|
||||
return "${fileSize ~/ (1024 * 1024 * 1024)} GB";
|
||||
} else if (fileSize > 1024 * 1024) {
|
||||
return "${fileSize ~/ (1024 * 1024)} MB";
|
||||
} else if (fileSize > 1024) {
|
||||
return "${fileSize ~/ 1024} KB";
|
||||
}
|
||||
return "$fileSize B";
|
||||
}
|
||||
}
|
||||
24
pubspec.lock
24
pubspec.lock
@@ -33,6 +33,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
background_downloader:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: background_downloader
|
||||
sha256: "3a796f29f0834b3e5698e7ac2a39e04939734395420349ff22e1ac2c73a0f73d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.2.1"
|
||||
base58check:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -580,6 +588,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -605,7 +621,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
@@ -651,13 +667,13 @@ packages:
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.5"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -64,6 +64,9 @@ dependencies:
|
||||
searchfield: ^1.2.7
|
||||
# webview_cef: ^0.2.2
|
||||
flutter_font_icons: ^2.2.7
|
||||
path_provider: ^2.1.5
|
||||
background_downloader: ^9.2.1
|
||||
mime: ^2.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_launcher_icons: ^0.13.1
|
||||
|
||||
Reference in New Issue
Block a user