|
|
|
import 'dart:io';
|
|
|
|
import 'dart:isolate';
|
|
|
|
import 'dart:ui';
|
|
|
|
|
|
|
|
import 'package:common_utils/common_utils.dart';
|
|
|
|
import 'package:device_info/device_info.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_picker/Picker.dart';
|
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
...
|
...
|
@@ -6,11 +11,15 @@ import 'package:one_key/res/colors.dart'; |
|
|
|
import 'package:one_key/widgets/round_button.dart';
|
|
|
|
import 'package:one_key/widgets/system_app_bar.dart';
|
|
|
|
import 'package:one_key/widgets/v_empty_view.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
|
|
|
|
import '../../../../utils/dialog_util.dart';
|
|
|
|
import '../../../../utils/screen_util.dart';
|
|
|
|
import '../../../../utils/utils.dart';
|
|
|
|
import '../../../../widgets/h_empty_view.dart';
|
|
|
|
import 'package:flutter_downloader/flutter_downloader.dart';
|
|
|
|
import 'package:android_path_provider/android_path_provider.dart';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 导出预订数据
|
|
...
|
...
|
@@ -31,6 +40,172 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { |
|
|
|
|
|
|
|
List<String> data = ['到店时间', '下单时间'];
|
|
|
|
int timeIndex;
|
|
|
|
ReceivePort _port = ReceivePort();
|
|
|
|
String _localPath;
|
|
|
|
|
|
|
|
String taskId;
|
|
|
|
DownloadTaskStatus status;
|
|
|
|
int progress;
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
|
|
|
|
_bindBackgroundIsolate();
|
|
|
|
|
|
|
|
FlutterDownloader.registerCallback(downloadCallback, step: 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
_unbindBackgroundIsolate();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
@pragma('vm:entry-point')
|
|
|
|
static void downloadCallback(
|
|
|
|
String id,
|
|
|
|
int status,
|
|
|
|
int progress,
|
|
|
|
) {
|
|
|
|
print(
|
|
|
|
'Callback on background isolate: '
|
|
|
|
'task ($id) is in status ($status) and process ($progress)',
|
|
|
|
);
|
|
|
|
|
|
|
|
IsolateNameServer.lookupPortByName('downloader_send_port')
|
|
|
|
?.send([id, status, progress]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 根据taskId打开下载文件
|
|
|
|
Future<bool> _openDownloadedFile(taskId) {
|
|
|
|
return FlutterDownloader.open(taskId: taskId);
|
|
|
|
}
|
|
|
|
|
|
|
|
void _bindBackgroundIsolate() {
|
|
|
|
final isSuccess = IsolateNameServer.registerPortWithName(
|
|
|
|
_port.sendPort,
|
|
|
|
'downloader_send_port',
|
|
|
|
);
|
|
|
|
if (!isSuccess) {
|
|
|
|
_unbindBackgroundIsolate();
|
|
|
|
_bindBackgroundIsolate();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_port.listen((dynamic data) {
|
|
|
|
taskId = (data as List<dynamic>)[0] as String;
|
|
|
|
status = DownloadTaskStatus(data[1] as int);
|
|
|
|
progress = data[2] as int;
|
|
|
|
|
|
|
|
print(
|
|
|
|
'Callback on UI isolate: '
|
|
|
|
'task ($taskId) is in status ($status) and process ($progress)',
|
|
|
|
);
|
|
|
|
if (status == DownloadTaskStatus.undefined) {
|
|
|
|
// _requestDownload(task);
|
|
|
|
} else if (status == DownloadTaskStatus.running) {
|
|
|
|
// _pauseDownload(task);
|
|
|
|
} else if (status == DownloadTaskStatus.paused) {
|
|
|
|
// _resumeDownload(task);
|
|
|
|
} else if (status == DownloadTaskStatus.complete ||
|
|
|
|
status == DownloadTaskStatus.canceled) {
|
|
|
|
// _delete(task);
|
|
|
|
// 显示是否打开的对话框
|
|
|
|
showDialog(
|
|
|
|
// 设置点击 dialog 外部不取消 dialog,默认能够取消
|
|
|
|
barrierDismissible: false,
|
|
|
|
context: context,
|
|
|
|
builder: (context) => AlertDialog(
|
|
|
|
title: Text('提示'),
|
|
|
|
// 标题文字样式
|
|
|
|
content: Text('文件下载完成,是否打开?'),
|
|
|
|
// 内容文字样式
|
|
|
|
backgroundColor: MyColours.color_ffffff,
|
|
|
|
elevation: 8.0,
|
|
|
|
// 投影的阴影高度
|
|
|
|
semanticLabel: 'Label',
|
|
|
|
// 这个用于无障碍下弹出 dialog 的提示
|
|
|
|
shape: Border.all(),
|
|
|
|
// dialog 的操作按钮,actions 的个数尽量控制不要过多,否则会溢出 `Overflow`
|
|
|
|
actions: <Widget>[
|
|
|
|
// 点击取消按钮
|
|
|
|
InkWell(
|
|
|
|
onTap: () => Navigator.pop(context), child: Text('取消')),
|
|
|
|
// 点击打开按钮
|
|
|
|
InkWell(
|
|
|
|
onTap: () {
|
|
|
|
Navigator.pop(context);
|
|
|
|
// 打开文件
|
|
|
|
_openDownloadedFile(taskId).then((success) {
|
|
|
|
if (!success) {
|
|
|
|
Utils.showToast('Cannot open this file');
|
|
|
|
// Scaffold.of(context).showSnackBar(SnackBar(
|
|
|
|
// content: Text('Cannot open this file')));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
child: Text('打开')),
|
|
|
|
],
|
|
|
|
));
|
|
|
|
} else if (status == DownloadTaskStatus.failed) {
|
|
|
|
// _retryDownload(task);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _prepareSaveDir() async {
|
|
|
|
_localPath = (await _getSavedDir());
|
|
|
|
final savedDir = Directory(_localPath);
|
|
|
|
if (!savedDir.existsSync()) {
|
|
|
|
await savedDir.create();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<String> _getSavedDir() async {
|
|
|
|
String externalStorageDirPath;
|
|
|
|
|
|
|
|
if (Platform.isAndroid) {
|
|
|
|
try {
|
|
|
|
externalStorageDirPath = await AndroidPathProvider.downloadsPath;
|
|
|
|
} catch (err, st) {
|
|
|
|
print('failed to get downloads path: $err, $st');
|
|
|
|
|
|
|
|
final directory = await getExternalStorageDirectory();
|
|
|
|
externalStorageDirPath = directory?.path;
|
|
|
|
}
|
|
|
|
} else if (Platform.isIOS) {
|
|
|
|
externalStorageDirPath =
|
|
|
|
(await getApplicationDocumentsDirectory()).absolute.path;
|
|
|
|
}
|
|
|
|
return externalStorageDirPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<bool> _checkPermission() async {
|
|
|
|
if (Platform.isIOS) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Platform.isAndroid) {
|
|
|
|
final info = await DeviceInfoPlugin().androidInfo;
|
|
|
|
if (info.version.sdkInt > 28) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
final status = await Permission.storage.status;
|
|
|
|
if (status == PermissionStatus.granted) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
final result = await Permission.storage.request();
|
|
|
|
return result == PermissionStatus.granted;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw StateError('unknown platform');
|
|
|
|
}
|
|
|
|
|
|
|
|
void _unbindBackgroundIsolate() {
|
|
|
|
IsolateNameServer.removePortNameMapping('downloader_send_port');
|
|
|
|
}
|
|
|
|
|
|
|
|
///时间选择
|
|
|
|
Widget _select(String title, String hintText, GestureTapCallback onTap) {
|
|
...
|
...
|
@@ -124,7 +299,12 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { |
|
|
|
// controller: controller,
|
|
|
|
child: Column(
|
|
|
|
children: [
|
|
|
|
VEmptyView(10),
|
|
|
|
(status == DownloadTaskStatus.running ||
|
|
|
|
status == DownloadTaskStatus.paused)
|
|
|
|
? LinearProgressIndicator(
|
|
|
|
value: progress / 100,
|
|
|
|
)
|
|
|
|
: VEmptyView(10),
|
|
|
|
Container(
|
|
|
|
padding: EdgeInsets.only(left: w(16)),
|
|
|
|
color: MyColours.color_ffffff,
|
|
...
|
...
|
@@ -234,6 +414,24 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { |
|
|
|
radius: r(10),
|
|
|
|
fontSize: 32,
|
|
|
|
isBold: true,
|
|
|
|
onPressed: () async {
|
|
|
|
bool _permissionReady = await _checkPermission();
|
|
|
|
if (_permissionReady) {
|
|
|
|
await _prepareSaveDir();
|
|
|
|
}
|
|
|
|
taskId = await FlutterDownloader.enqueue(
|
|
|
|
url:
|
|
|
|
'http://englishonlineclub.com/pdf/iOS%20Programming%20-%20The%20Big%20Nerd%20Ranch%20Guide%20(6th%20Edition)%20[EnglishOnlineClub.com].pdf',
|
|
|
|
headers: {
|
|
|
|
'auth': 'test_for_sql_encoding'
|
|
|
|
}, // optional: header send with url (auth token etc)
|
|
|
|
savedDir: _localPath,
|
|
|
|
showNotification:
|
|
|
|
true, // show download progress in status bar (for Android)
|
|
|
|
openFileFromNotification:
|
|
|
|
true, // click on notification to open downloaded file (for Android)
|
|
|
|
);
|
|
|
|
},
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
...
|
...
|
|