export all images to albums
This commit is contained in:
parent
9e2027ef45
commit
e3af9c25f1
|
@ -1,21 +1,24 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="niuhuan.pikapi">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="pikapi"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
android:requestLegacyExternalStorage="true">
|
||||
<!-- requestLegacyExternalStorage="true" api29 down -->
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
|
@ -23,8 +26,7 @@
|
|||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
android:resource="@style/NormalTheme" />
|
||||
<!-- Displays an Android View that continues showing the launch screen
|
||||
Drawable until Flutter paints its first frame, then this splash
|
||||
screen fades out. A splash screen is useful to avoid any visual
|
||||
|
@ -32,17 +34,16 @@
|
|||
Flutter's first frame. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
android:resource="@drawable/launch_background"
|
||||
/>
|
||||
android:resource="@drawable/launch_background" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2"/>
|
||||
android:value="2" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
@ -13,6 +13,7 @@ import android.provider.MediaStore
|
|||
import android.view.Display
|
||||
import android.view.KeyEvent
|
||||
import androidx.annotation.NonNull
|
||||
import com.google.gson.Gson
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
|
@ -22,7 +23,12 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.newSingleThreadContext
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import mobile.Mobile
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
import java.util.concurrent.locks.Condition
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
class MainActivity : FlutterActivity() {
|
||||
|
||||
|
@ -60,8 +66,12 @@ class MainActivity : FlutterActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private val resourceQueue: LinkedBlockingQueue<Any?> = LinkedBlockingQueue()
|
||||
private var cacheDir: String? = null
|
||||
|
||||
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
cacheDir = context!!.cacheDir.absolutePath
|
||||
Mobile.initApplication(context!!.filesDir.absolutePath)
|
||||
// Method Channel
|
||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "method").setMethodCallHandler { call, result ->
|
||||
|
@ -86,6 +96,9 @@ class MainActivity : FlutterActivity() {
|
|||
uiMode()
|
||||
}
|
||||
"androidGetVersion" -> Build.VERSION.SDK_INT
|
||||
// "exportComicDownloadAndroidQ" -> {
|
||||
// exportComicDownloadAndroidQ(call.argument("comicId")!!)
|
||||
// }
|
||||
else -> {
|
||||
notImplementedToken
|
||||
}
|
||||
|
@ -194,7 +207,7 @@ class MainActivity : FlutterActivity() {
|
|||
private fun setMode(string: String) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
mixDisplay()?.let { display ->
|
||||
if (string == ""){
|
||||
if (string == "") {
|
||||
uiThreadHandler.post {
|
||||
window.attributes = window.attributes.also { attr ->
|
||||
attr.preferredDisplayModeId = 0
|
||||
|
@ -283,12 +296,63 @@ class MainActivity : FlutterActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
// 安卓11以上使用了 MANAGE_EXTERNAL_STORAGE 权限来管理整个外置存储 (危险权限)
|
||||
|
||||
fun main(){
|
||||
startActivityForResult(Intent(Intent.ACTION_GET_CONTENT).also {
|
||||
it.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
},1)
|
||||
}
|
||||
|
||||
// private var tmpComicId: String? = null
|
||||
// private val exportComicDownloadAndroidQRequestCode = 2
|
||||
//
|
||||
// private fun exportComicDownloadAndroidQ(comicId: String) {
|
||||
// val title = Mobile.flatInvoke("specialDownloadTitle", comicId)
|
||||
// var fileName = title
|
||||
// fileName = fileName.replace('/', '_')
|
||||
// fileName = fileName.replace('\\', '_')
|
||||
// fileName = fileName.replace('*', '_')
|
||||
// fileName = fileName.replace('?', '_')
|
||||
// fileName = fileName.replace('<', '_')
|
||||
// fileName = fileName.replace('>', '_')
|
||||
// fileName = fileName.replace('|', '_')
|
||||
// fileName = fileName + "_" + System.currentTimeMillis() + ".zip"
|
||||
// tmpComicId = comicId
|
||||
// startActivityForResult(Intent(Intent.ACTION_CREATE_DOCUMENT).also {
|
||||
// it.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
// it.type = "application/octet-stream"
|
||||
// it.putExtra(Intent.EXTRA_TITLE, fileName)
|
||||
// }, exportComicDownloadAndroidQRequestCode)
|
||||
// val result = resourceQueue.take()
|
||||
// if (result is Throwable) {
|
||||
// throw result
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
// pool.submit {
|
||||
// try {
|
||||
// if (resultCode === RESULT_OK && data != null) {
|
||||
// when (requestCode) {
|
||||
// exportComicDownloadAndroidQRequestCode -> {
|
||||
// contentResolver.openOutputStream(data.data!!)?.use { os ->
|
||||
// val path = Mobile.flatInvoke("exportComicDownload", Gson().toJson(HashMap<Any, Any?>().also { map ->
|
||||
// map["comicId"] = tmpComicId
|
||||
// map["dir"] = cacheDir
|
||||
// }))
|
||||
// try {
|
||||
// FileInputStream(path).copyTo(os)
|
||||
// } finally {
|
||||
// File(path).delete()
|
||||
// }
|
||||
// }
|
||||
// resourceQueue.put("OK")
|
||||
// }
|
||||
// else -> resourceQueue.put(Exception("WTF"))
|
||||
// }
|
||||
// } else {
|
||||
// resourceQueue.put(Exception("NOT OK"))
|
||||
// }
|
||||
// } catch (e: Throwable) {
|
||||
// resourceQueue.put(Exception(e))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"path"
|
||||
"pgo/pikapi/const_value"
|
||||
"pgo/pikapi/database/comic_center"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -67,7 +68,7 @@ func exportComicUsingSocketExit() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func exportComicDownload(params string) error {
|
||||
func exportComicDownload(params string) (filePath string, err error) {
|
||||
var paramsStruct struct {
|
||||
ComicId string `json:"comicId"`
|
||||
Dir string `json:"dir"`
|
||||
|
@ -78,29 +79,43 @@ func exportComicDownload(params string) error {
|
|||
println(fmt.Sprintf("导出 %s 到 %s", comicId, dir))
|
||||
comic, err := comic_center.FindComicDownloadById(comicId)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
if comic == nil {
|
||||
return errors.New("not found")
|
||||
err = errors.New("not found")
|
||||
return
|
||||
}
|
||||
if !comic.DownloadFinished {
|
||||
return errors.New("not download finish")
|
||||
err = errors.New("not download finish")
|
||||
return
|
||||
}
|
||||
filePath := path.Join(dir, fmt.Sprintf("%s-%s.zip", comic.Title, time.Now().Format("2006_01_02_15_04_05.999")))
|
||||
filePath = path.Join(dir, fmt.Sprintf("%s-%s.zip", reasonablePath(comic.Title), time.Now().Format("2006_01_02_15_04_05.999")))
|
||||
println(fmt.Sprintf("ZIP : %s", filePath))
|
||||
fileStream, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
defer fileStream.Close()
|
||||
zipWriter := zip.NewWriter(fileStream)
|
||||
defer zipWriter.Close()
|
||||
return exportComicDownloadFetch(comicId, func(path string, size int64) (io.Writer, error) {
|
||||
err = exportComicDownloadFetch(comicId, func(path string, size int64) (io.Writer, error) {
|
||||
header := tar.Header{}
|
||||
header.Name = path
|
||||
header.Size = size
|
||||
return zipWriter.Create(path)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func reasonablePath(title string) string {
|
||||
title = strings.ReplaceAll(title, "\\", "_")
|
||||
title = strings.ReplaceAll(title, "/", "_")
|
||||
title = strings.ReplaceAll(title, "*", "_")
|
||||
title = strings.ReplaceAll(title, "?", "_")
|
||||
title = strings.ReplaceAll(title, "<", "_")
|
||||
title = strings.ReplaceAll(title, ">", "_")
|
||||
title = strings.ReplaceAll(title, "|", "_")
|
||||
return title
|
||||
}
|
||||
|
||||
func exportComicDownloadFetch(comicId string, onWriteFile func(path string, size int64) (io.Writer, error)) error {
|
||||
|
@ -367,7 +382,7 @@ func exportComicDownloadToJPG(params string) error {
|
|||
if !comic.DownloadFinished {
|
||||
return errors.New("not download finish")
|
||||
}
|
||||
dirPath := path.Join(dir, fmt.Sprintf("%s-%s", comic.Title, time.Now().Format("2006_01_02_15_04_05.999")))
|
||||
dirPath := path.Join(dir, fmt.Sprintf("%s-%s", reasonablePath(comic.Title), time.Now().Format("2006_01_02_15_04_05.999")))
|
||||
println(fmt.Sprintf("DIR : %s", dirPath))
|
||||
err = os.Mkdir(dirPath, const_value.CreateDirMode)
|
||||
if err != nil {
|
||||
|
|
|
@ -575,7 +575,7 @@ func FlatInvoke(method string, params string) (string, error) {
|
|||
case "resetAllDownloads":
|
||||
return "", comic_center.ResetAll()
|
||||
case "exportComicDownload":
|
||||
return "", exportComicDownload(params)
|
||||
return exportComicDownload(params)
|
||||
case "exportComicDownloadToJPG":
|
||||
return "", exportComicDownloadToJPG(params)
|
||||
case "exportComicUsingSocket":
|
||||
|
@ -599,6 +599,8 @@ func FlatInvoke(method string, params string) (string, error) {
|
|||
return downloadGame(params)
|
||||
case "convertImageToJPEG100":
|
||||
return "", convertImageToJPEG100(params)
|
||||
case "specialDownloadTitle":
|
||||
return specialDownloadTitle(params)
|
||||
}
|
||||
return "", errors.New("method not found : " + method)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package controller
|
||||
|
||||
import "pgo/pikapi/database/comic_center"
|
||||
|
||||
func specialDownloadTitle(comicId string) (string, error) {
|
||||
info, err := comic_center.DownloadInfo(comicId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return info.Title, nil
|
||||
}
|
|
@ -586,6 +586,20 @@ func DeleteRemoteImages(images []RemoteImage) error {
|
|||
return db.Unscoped().Model(&RemoteImage{}).Delete("id in ?", ids).Error
|
||||
}
|
||||
|
||||
func DownloadInfo(comicId string) (*ComicDownload, error) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
var download ComicDownload
|
||||
err := db.First(&download, "id = ?", comicId).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &download, nil
|
||||
}
|
||||
|
||||
func VACUUM() error {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:filesystem_picker/filesystem_picker.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:pikapi/basic/Common.dart';
|
||||
import 'package:pikapi/basic/config/Platform.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'Method.dart';
|
||||
import 'config/ChooserRoot.dart';
|
||||
|
@ -57,6 +58,16 @@ Future<dynamic> saveImage(String path, BuildContext context) async {
|
|||
}
|
||||
}
|
||||
|
||||
Future<dynamic> saveImageQuiet(String path, BuildContext context) async {
|
||||
if (Platform.isIOS) {
|
||||
return method.iosSaveFileToImage(path);
|
||||
} else if (Platform.isAndroid) {
|
||||
return _saveImageAndroid(path, context);
|
||||
} else {
|
||||
throw Exception("only mobile");
|
||||
}
|
||||
}
|
||||
|
||||
Future<dynamic> _saveImageAndroid(String path, BuildContext context) async {
|
||||
var p = await Permission.storage.request();
|
||||
if (!p.isGranted) {
|
||||
|
@ -68,10 +79,15 @@ Future<dynamic> _saveImageAndroid(String path, BuildContext context) async {
|
|||
/// 选择一个文件夹用于保存文件
|
||||
Future<String?> chooseFolder(BuildContext context) async {
|
||||
if (Platform.isAndroid) {
|
||||
var p = await Permission.storage.request();
|
||||
if (!p.isGranted) {
|
||||
if (androidVersion >= 30) {
|
||||
if (!(await Permission.manageExternalStorage.request()).isGranted) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
if (!(await Permission.storage.request()).isGranted) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FilesystemPicker.open(
|
||||
title: '选择一个文件夹',
|
||||
|
|
|
@ -429,6 +429,12 @@ class Method {
|
|||
});
|
||||
}
|
||||
|
||||
Future<dynamic> exportComicDownloadAndroidQ(String comicId) {
|
||||
return _channel.invokeMethod("exportComicDownloadAndroidQ", {
|
||||
"comicId": comicId,
|
||||
});
|
||||
}
|
||||
|
||||
Future<dynamic> exportComicDownloadToJPG(String comicId, String dir) {
|
||||
return _flatInvoke("exportComicDownloadToJPG", {
|
||||
"comicId": comicId,
|
||||
|
|
|
@ -23,7 +23,10 @@ String currentChooserRoot() {
|
|||
} else if (Platform.isLinux) {
|
||||
return '/';
|
||||
} else if (Platform.isAndroid) {
|
||||
return '/storage/emulated/0/Download';
|
||||
// if (androidVersion >= 30) {
|
||||
// return '/storage/emulated/0/Download';
|
||||
// }
|
||||
return '/storage/emulated/0';
|
||||
} else {
|
||||
throw 'error';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
import 'dart:io';
|
||||
|
||||
import '../Method.dart';
|
||||
|
||||
int androidVersion = 0;
|
||||
|
||||
Future<void> initPlatform()async{
|
||||
if (Platform.isAndroid) {
|
||||
androidVersion = await method.androidGetVersion();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import 'package:event/event.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../Method.dart';
|
||||
import 'Platform.dart';
|
||||
|
||||
// 主题包
|
||||
abstract class _ThemePackage {
|
||||
|
@ -124,7 +125,6 @@ final _themePackages = <_ThemePackage>[
|
|||
// 主题更换事件
|
||||
var themeEvent = Event<EventArgs>();
|
||||
|
||||
int _androidVersion = 1;
|
||||
String? _themeCode;
|
||||
ThemeData? _themeData;
|
||||
bool _androidNightMode = false;
|
||||
|
@ -161,9 +161,7 @@ void _changeThemeByCode(String themeCode) {
|
|||
const _nightModePropertyName = "androidNightMode";
|
||||
|
||||
Future<dynamic> initTheme() async {
|
||||
if (Platform.isAndroid) {
|
||||
_androidVersion = await method.androidGetVersion();
|
||||
if (_androidVersion >= 29) {
|
||||
if (androidVersion >= 29) {
|
||||
_androidNightMode =
|
||||
(await method.loadProperty(_nightModePropertyName, "false")) ==
|
||||
"true";
|
||||
|
@ -173,7 +171,6 @@ Future<dynamic> initTheme() async {
|
|||
themeEvent.broadcast();
|
||||
});
|
||||
}
|
||||
}
|
||||
_changeThemeByCode(await method.loadTheme());
|
||||
}
|
||||
|
||||
|
@ -185,7 +182,7 @@ Future<dynamic> chooseTheme(BuildContext buildContext) async {
|
|||
return StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
var list = <SimpleDialogOption>[];
|
||||
if (_androidVersion >= 29) {
|
||||
if (androidVersion >= 29) {
|
||||
var onChange = (bool? v) async {
|
||||
if (v != null) {
|
||||
await method.saveProperty(
|
||||
|
|
|
@ -2,10 +2,13 @@ import 'dart:async';
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:pikapi/basic/Channels.dart';
|
||||
import 'package:pikapi/basic/Common.dart';
|
||||
import 'package:pikapi/basic/Cross.dart';
|
||||
import 'package:pikapi/basic/Entities.dart';
|
||||
import 'package:pikapi/basic/Method.dart';
|
||||
import 'package:pikapi/basic/config/Platform.dart';
|
||||
import 'package:pikapi/screens/DownloadExportToSocketScreen.dart';
|
||||
|
||||
import 'components/ContentError.dart';
|
||||
|
@ -117,12 +120,12 @@ class _DownloadExportToFileScreenState
|
|||
}
|
||||
|
||||
List<Widget> _buildExportToFileButtons() {
|
||||
List<Widget> widgets = [];
|
||||
if (Platform.isWindows ||
|
||||
Platform.isMacOS ||
|
||||
Platform.isLinux ||
|
||||
Platform.isAndroid) {
|
||||
return [
|
||||
MaterialButton(
|
||||
widgets.add(MaterialButton(
|
||||
onPressed: () async {
|
||||
String? path = await chooseFolder(context);
|
||||
print("path $path");
|
||||
|
@ -150,9 +153,9 @@ class _DownloadExportToFileScreenState
|
|||
}
|
||||
},
|
||||
child: _buildButtonInner('导出到HTML+JPG\n(可直接在相册中打开观看)'),
|
||||
),
|
||||
Container(height: 10),
|
||||
MaterialButton(
|
||||
));
|
||||
widgets.add(Container(height: 10));
|
||||
widgets.add(MaterialButton(
|
||||
onPressed: () async {
|
||||
String? path = await chooseFolder(context);
|
||||
print("path $path");
|
||||
|
@ -180,11 +183,55 @@ class _DownloadExportToFileScreenState
|
|||
}
|
||||
},
|
||||
child: _buildButtonInner('导出到HTML.zip\n(可从其他设备导入 / 解压后可阅读)'),
|
||||
),
|
||||
Container(height: 10),
|
||||
];
|
||||
));
|
||||
widgets.add(Container(height: 10));
|
||||
}
|
||||
return [];
|
||||
if (Platform.isIOS || Platform.isAndroid) {
|
||||
widgets.add(MaterialButton(
|
||||
onPressed: () async {
|
||||
if (!(await confirmDialog(context, "导出确认", "将本漫画所有图片到相册?"))) {
|
||||
return;
|
||||
}
|
||||
if (!(await Permission.storage.request()).isGranted) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
setState(() {
|
||||
exporting = true;
|
||||
});
|
||||
// 导出所有图片数据
|
||||
var count = 0;
|
||||
List<DownloadEp> eps = await method.downloadEpList(widget.comicId);
|
||||
for (var i = 0; i < eps.length; i++) {
|
||||
var pics = await method.downloadPicturesByEpId(eps[i].id);
|
||||
for (var j = 0; j < pics.length; j++) {
|
||||
setState(() {
|
||||
exportMessage = "导出图片 ${count++} 张";
|
||||
});
|
||||
await saveImageQuiet(
|
||||
await method.downloadImagePath(pics[j].localPath),
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
exportResult = "导出成功";
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
exportResult = "导出失败 $e";
|
||||
});
|
||||
} finally {
|
||||
setState(() {
|
||||
exporting = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: _buildButtonInner('将所有图片到处到手机相机'),
|
||||
));
|
||||
widgets.add(Container(height: 10));
|
||||
}
|
||||
return widgets;
|
||||
}
|
||||
|
||||
Widget _buildButtonInner(String text) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:pikapi/basic/config/FullScreenAction.dart';
|
|||
import 'package:pikapi/basic/config/FullScreenUI.dart';
|
||||
import 'package:pikapi/basic/config/KeyboardController.dart';
|
||||
import 'package:pikapi/basic/config/PagerAction.dart';
|
||||
import 'package:pikapi/basic/config/Platform.dart';
|
||||
import 'package:pikapi/basic/config/Proxy.dart';
|
||||
import 'package:pikapi/basic/config/Quality.dart';
|
||||
import 'package:pikapi/basic/config/ReaderDirection.dart';
|
||||
|
@ -37,6 +38,7 @@ class _InitScreenState extends State<InitScreen> {
|
|||
|
||||
Future<dynamic> _init() async {
|
||||
// 初始化配置文件
|
||||
await initPlatform(); // 必须第一个初始化, 加载设备信息
|
||||
await autoClean();
|
||||
await initAddress();
|
||||
await initProxy();
|
||||
|
|
Loading…
Reference in New Issue