Commit c7967a90f2dd5b3c14019f271a8cb84e93178b40

Authored by wdn127929
1 parent f3f48340

导出excel

@@ -76,10 +76,10 @@ @@ -76,10 +76,10 @@
76 android:value="2" /> 76 android:value="2" />
77 77
78 78
79 - <!-- <provider 79 + <provider
80 android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider" 80 android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
81 android:authorities="${applicationId}.flutter_downloader.provider" 81 android:authorities="${applicationId}.flutter_downloader.provider"
82 - android:exported="true" 82 + android:exported="false"
83 android:grantUriPermissions="true"> 83 android:grantUriPermissions="true">
84 <meta-data 84 <meta-data
85 android:name="android.support.FILE_PROVIDER_PATHS" 85 android:name="android.support.FILE_PROVIDER_PATHS"
@@ -90,7 +90,7 @@ @@ -90,7 +90,7 @@
90 <provider 90 <provider
91 android:name="androidx.startup.InitializationProvider" 91 android:name="androidx.startup.InitializationProvider"
92 android:authorities="${applicationId}.androidx-startup" 92 android:authorities="${applicationId}.androidx-startup"
93 - android:exported="true" 93 + android:exported="false"
94 tools:node="merge"> 94 tools:node="merge">
95 <meta-data 95 <meta-data
96 android:name="androidx.work.WorkManagerInitializer" 96 android:name="androidx.work.WorkManagerInitializer"
@@ -102,11 +102,11 @@ @@ -102,11 +102,11 @@
102 <provider 102 <provider
103 android:name="vn.hunghd.flutterdownloader.FlutterDownloaderInitializer" 103 android:name="vn.hunghd.flutterdownloader.FlutterDownloaderInitializer"
104 android:authorities="${applicationId}.flutter-downloader-init" 104 android:authorities="${applicationId}.flutter-downloader-init"
105 - android:exported="true"> 105 + android:exported="false">
106 <meta-data 106 <meta-data
107 android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS" 107 android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS"
108 android:value="5" /> 108 android:value="5" />
109 - </provider> --> 109 + </provider>
110 <!-- End FlutterDownloader customization --> 110 <!-- End FlutterDownloader customization -->
111 <meta-data 111 <meta-data
112 android:name="com.amap.api.v2.apikey" 112 android:name="com.amap.api.v2.apikey"
@@ -6,6 +6,7 @@ import 'package:dio/dio.dart'; @@ -6,6 +6,7 @@ import 'package:dio/dio.dart';
6 import 'package:fluro/fluro.dart'; 6 import 'package:fluro/fluro.dart';
7 import 'package:flutter/material.dart' hide Router; 7 import 'package:flutter/material.dart' hide Router;
8 import 'package:flutter_bugly/flutter_bugly.dart'; 8 import 'package:flutter_bugly/flutter_bugly.dart';
  9 +import 'package:flutter_downloader/flutter_downloader.dart';
9 import 'package:flutter_easyrefresh/ball_pulse_footer.dart'; 10 import 'package:flutter_easyrefresh/ball_pulse_footer.dart';
10 import 'package:flutter_easyrefresh/easy_refresh.dart'; 11 import 'package:flutter_easyrefresh/easy_refresh.dart';
11 import 'package:flutter_easyrefresh/material_header.dart'; 12 import 'package:flutter_easyrefresh/material_header.dart';
@@ -79,6 +80,8 @@ Future<void> main() async { @@ -79,6 +80,8 @@ Future<void> main() async {
79 // // _requestPermissions(); 80 // // _requestPermissions();
80 // Utils.changeStatusColor(); 81 // Utils.changeStatusColor();
81 82
  83 + await FlutterDownloader.initialize(debug: true, ignoreSsl: true);
  84 +
82 await App.initSp(); 85 await App.initSp();
83 SystemChrome.setPreferredOrientations( 86 SystemChrome.setPreferredOrientations(
84 [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]) 87 [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
@@ -142,7 +145,6 @@ Future<void> main() async { @@ -142,7 +145,6 @@ Future<void> main() async {
142 }); 145 });
143 } 146 }
144 147
145 -  
146 class MyApp extends StatefulWidget { 148 class MyApp extends StatefulWidget {
147 @override 149 @override
148 State<StatefulWidget> createState() { 150 State<StatefulWidget> createState() {
  1 +import 'dart:io';
  2 +import 'dart:isolate';
  3 +import 'dart:ui';
  4 +
1 import 'package:common_utils/common_utils.dart'; 5 import 'package:common_utils/common_utils.dart';
  6 +import 'package:device_info/device_info.dart';
2 import 'package:flutter/material.dart'; 7 import 'package:flutter/material.dart';
3 import 'package:flutter_picker/Picker.dart'; 8 import 'package:flutter_picker/Picker.dart';
4 import 'package:flutter_screenutil/flutter_screenutil.dart'; 9 import 'package:flutter_screenutil/flutter_screenutil.dart';
@@ -6,11 +11,15 @@ import 'package:one_key/res/colors.dart'; @@ -6,11 +11,15 @@ import 'package:one_key/res/colors.dart';
6 import 'package:one_key/widgets/round_button.dart'; 11 import 'package:one_key/widgets/round_button.dart';
7 import 'package:one_key/widgets/system_app_bar.dart'; 12 import 'package:one_key/widgets/system_app_bar.dart';
8 import 'package:one_key/widgets/v_empty_view.dart'; 13 import 'package:one_key/widgets/v_empty_view.dart';
  14 +import 'package:path_provider/path_provider.dart';
  15 +import 'package:permission_handler/permission_handler.dart';
9 16
10 import '../../../../utils/dialog_util.dart'; 17 import '../../../../utils/dialog_util.dart';
11 import '../../../../utils/screen_util.dart'; 18 import '../../../../utils/screen_util.dart';
12 import '../../../../utils/utils.dart'; 19 import '../../../../utils/utils.dart';
13 import '../../../../widgets/h_empty_view.dart'; 20 import '../../../../widgets/h_empty_view.dart';
  21 +import 'package:flutter_downloader/flutter_downloader.dart';
  22 +import 'package:android_path_provider/android_path_provider.dart';
14 23
15 /** 24 /**
16 * 导出预订数据 25 * 导出预订数据
@@ -31,6 +40,172 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -31,6 +40,172 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
31 40
32 List<String> data = ['到店时间', '下单时间']; 41 List<String> data = ['到店时间', '下单时间'];
33 int timeIndex; 42 int timeIndex;
  43 + ReceivePort _port = ReceivePort();
  44 + String _localPath;
  45 +
  46 + String taskId;
  47 + DownloadTaskStatus status;
  48 + int progress;
  49 +
  50 + @override
  51 + void initState() {
  52 + super.initState();
  53 +
  54 + _bindBackgroundIsolate();
  55 +
  56 + FlutterDownloader.registerCallback(downloadCallback, step: 1);
  57 + }
  58 +
  59 + @override
  60 + void dispose() {
  61 + _unbindBackgroundIsolate();
  62 + super.dispose();
  63 + }
  64 +
  65 + @pragma('vm:entry-point')
  66 + static void downloadCallback(
  67 + String id,
  68 + int status,
  69 + int progress,
  70 + ) {
  71 + print(
  72 + 'Callback on background isolate: '
  73 + 'task ($id) is in status ($status) and process ($progress)',
  74 + );
  75 +
  76 + IsolateNameServer.lookupPortByName('downloader_send_port')
  77 + ?.send([id, status, progress]);
  78 + }
  79 +
  80 + // 根据taskId打开下载文件
  81 + Future<bool> _openDownloadedFile(taskId) {
  82 + return FlutterDownloader.open(taskId: taskId);
  83 + }
  84 +
  85 + void _bindBackgroundIsolate() {
  86 + final isSuccess = IsolateNameServer.registerPortWithName(
  87 + _port.sendPort,
  88 + 'downloader_send_port',
  89 + );
  90 + if (!isSuccess) {
  91 + _unbindBackgroundIsolate();
  92 + _bindBackgroundIsolate();
  93 + return;
  94 + }
  95 + _port.listen((dynamic data) {
  96 + taskId = (data as List<dynamic>)[0] as String;
  97 + status = DownloadTaskStatus(data[1] as int);
  98 + progress = data[2] as int;
  99 +
  100 + print(
  101 + 'Callback on UI isolate: '
  102 + 'task ($taskId) is in status ($status) and process ($progress)',
  103 + );
  104 + if (status == DownloadTaskStatus.undefined) {
  105 + // _requestDownload(task);
  106 + } else if (status == DownloadTaskStatus.running) {
  107 + // _pauseDownload(task);
  108 + } else if (status == DownloadTaskStatus.paused) {
  109 + // _resumeDownload(task);
  110 + } else if (status == DownloadTaskStatus.complete ||
  111 + status == DownloadTaskStatus.canceled) {
  112 + // _delete(task);
  113 + // 显示是否打开的对话框
  114 + showDialog(
  115 + // 设置点击 dialog 外部不取消 dialog,默认能够取消
  116 + barrierDismissible: false,
  117 + context: context,
  118 + builder: (context) => AlertDialog(
  119 + title: Text('提示'),
  120 + // 标题文字样式
  121 + content: Text('文件下载完成,是否打开?'),
  122 + // 内容文字样式
  123 + backgroundColor: MyColours.color_ffffff,
  124 + elevation: 8.0,
  125 + // 投影的阴影高度
  126 + semanticLabel: 'Label',
  127 + // 这个用于无障碍下弹出 dialog 的提示
  128 + shape: Border.all(),
  129 + // dialog 的操作按钮,actions 的个数尽量控制不要过多,否则会溢出 `Overflow`
  130 + actions: <Widget>[
  131 + // 点击取消按钮
  132 + InkWell(
  133 + onTap: () => Navigator.pop(context), child: Text('取消')),
  134 + // 点击打开按钮
  135 + InkWell(
  136 + onTap: () {
  137 + Navigator.pop(context);
  138 + // 打开文件
  139 + _openDownloadedFile(taskId).then((success) {
  140 + if (!success) {
  141 + Utils.showToast('Cannot open this file');
  142 + // Scaffold.of(context).showSnackBar(SnackBar(
  143 + // content: Text('Cannot open this file')));
  144 + }
  145 + });
  146 + },
  147 + child: Text('打开')),
  148 + ],
  149 + ));
  150 + } else if (status == DownloadTaskStatus.failed) {
  151 + // _retryDownload(task);
  152 + }
  153 + });
  154 + }
  155 +
  156 + Future<void> _prepareSaveDir() async {
  157 + _localPath = (await _getSavedDir());
  158 + final savedDir = Directory(_localPath);
  159 + if (!savedDir.existsSync()) {
  160 + await savedDir.create();
  161 + }
  162 + }
  163 +
  164 + Future<String> _getSavedDir() async {
  165 + String externalStorageDirPath;
  166 +
  167 + if (Platform.isAndroid) {
  168 + try {
  169 + externalStorageDirPath = await AndroidPathProvider.downloadsPath;
  170 + } catch (err, st) {
  171 + print('failed to get downloads path: $err, $st');
  172 +
  173 + final directory = await getExternalStorageDirectory();
  174 + externalStorageDirPath = directory?.path;
  175 + }
  176 + } else if (Platform.isIOS) {
  177 + externalStorageDirPath =
  178 + (await getApplicationDocumentsDirectory()).absolute.path;
  179 + }
  180 + return externalStorageDirPath;
  181 + }
  182 +
  183 + Future<bool> _checkPermission() async {
  184 + if (Platform.isIOS) {
  185 + return true;
  186 + }
  187 +
  188 + if (Platform.isAndroid) {
  189 + final info = await DeviceInfoPlugin().androidInfo;
  190 + if (info.version.sdkInt > 28) {
  191 + return true;
  192 + }
  193 +
  194 + final status = await Permission.storage.status;
  195 + if (status == PermissionStatus.granted) {
  196 + return true;
  197 + }
  198 +
  199 + final result = await Permission.storage.request();
  200 + return result == PermissionStatus.granted;
  201 + }
  202 +
  203 + throw StateError('unknown platform');
  204 + }
  205 +
  206 + void _unbindBackgroundIsolate() {
  207 + IsolateNameServer.removePortNameMapping('downloader_send_port');
  208 + }
34 209
35 ///时间选择 210 ///时间选择
36 Widget _select(String title, String hintText, GestureTapCallback onTap) { 211 Widget _select(String title, String hintText, GestureTapCallback onTap) {
@@ -124,7 +299,12 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -124,7 +299,12 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
124 // controller: controller, 299 // controller: controller,
125 child: Column( 300 child: Column(
126 children: [ 301 children: [
127 - VEmptyView(10), 302 + (status == DownloadTaskStatus.running ||
  303 + status == DownloadTaskStatus.paused)
  304 + ? LinearProgressIndicator(
  305 + value: progress / 100,
  306 + )
  307 + : VEmptyView(10),
128 Container( 308 Container(
129 padding: EdgeInsets.only(left: w(16)), 309 padding: EdgeInsets.only(left: w(16)),
130 color: MyColours.color_ffffff, 310 color: MyColours.color_ffffff,
@@ -234,6 +414,24 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> { @@ -234,6 +414,24 @@ class _ExportBookDataPageState extends State<ExportBookDataPage> {
234 radius: r(10), 414 radius: r(10),
235 fontSize: 32, 415 fontSize: 32,
236 isBold: true, 416 isBold: true,
  417 + onPressed: () async {
  418 + bool _permissionReady = await _checkPermission();
  419 + if (_permissionReady) {
  420 + await _prepareSaveDir();
  421 + }
  422 + taskId = await FlutterDownloader.enqueue(
  423 + url:
  424 + 'http://englishonlineclub.com/pdf/iOS%20Programming%20-%20The%20Big%20Nerd%20Ranch%20Guide%20(6th%20Edition)%20[EnglishOnlineClub.com].pdf',
  425 + headers: {
  426 + 'auth': 'test_for_sql_encoding'
  427 + }, // optional: header send with url (auth token etc)
  428 + savedDir: _localPath,
  429 + showNotification:
  430 + true, // show download progress in status bar (for Android)
  431 + openFileFromNotification:
  432 + true, // click on notification to open downloaded file (for Android)
  433 + );
  434 + },
237 ) 435 )
238 ], 436 ],
239 ), 437 ),
@@ -43,6 +43,13 @@ packages: @@ -43,6 +43,13 @@ packages:
43 url: "https://pub.flutter-io.cn" 43 url: "https://pub.flutter-io.cn"
44 source: hosted 44 source: hosted
45 version: "4.1.0" 45 version: "4.1.0"
  46 + android_path_provider:
  47 + dependency: "direct main"
  48 + description:
  49 + name: android_path_provider
  50 + url: "https://pub.flutter-io.cn"
  51 + source: hosted
  52 + version: "0.3.0"
46 archive: 53 archive:
47 dependency: transitive 54 dependency: transitive
48 description: 55 description:
@@ -531,6 +538,13 @@ packages: @@ -531,6 +538,13 @@ packages:
531 url: "https://pub.flutter-io.cn" 538 url: "https://pub.flutter-io.cn"
532 source: hosted 539 source: hosted
533 version: "3.3.0" 540 version: "3.3.0"
  541 + flutter_downloader:
  542 + dependency: "direct main"
  543 + description:
  544 + name: flutter_downloader
  545 + url: "https://pub.flutter-io.cn"
  546 + source: hosted
  547 + version: "1.10.5"
534 flutter_easyrefresh: 548 flutter_easyrefresh:
535 dependency: "direct main" 549 dependency: "direct main"
536 description: 550 description:
@@ -182,7 +182,8 @@ dependencies: @@ -182,7 +182,8 @@ dependencies:
182 # webview_flutter: ^2.0.13 182 # webview_flutter: ^2.0.13
183 # flutter_inappwebview: ^5.3.2 183 # flutter_inappwebview: ^5.3.2
184 flutter_inappwebview: ^5.7.2+3 184 flutter_inappwebview: ^5.7.2+3
185 - # flutter_downloader: ^1.7.1 185 + flutter_downloader: ^1.10.5
  186 + android_path_provider: ^0.3.0
186 # open_file: ^3.2.1 187 # open_file: ^3.2.1
187 188
188 webview_flutter: 189 webview_flutter: