Support pki
This commit is contained in:
parent
a246a3d423
commit
03f41bab0b
|
@ -52,6 +52,7 @@
|
|||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.pkz"
|
||||
|
@ -60,6 +61,25 @@
|
|||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.pkz"
|
||||
android:scheme="file" />
|
||||
|
||||
<data
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.pki"
|
||||
android:scheme="content" />
|
||||
<data
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.pki"
|
||||
android:scheme="file" />
|
||||
|
||||
<data
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.zip"
|
||||
android:scheme="content" />
|
||||
<data
|
||||
android:mimeType="*/*"
|
||||
android:pathPattern=".*\\.zip"
|
||||
android:scheme="file" />
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
|
|
|
@ -40,10 +40,14 @@
|
|||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>pkz</string>
|
||||
<string>pki</string>
|
||||
<string>zip</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<array>
|
||||
<string>text/vnd.niuhuan.pkz</string>
|
||||
<string>text/vnd.niuhuan.pki</string>
|
||||
<string>text/vnd.niuhuan.zip</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:uri_to_file/uri_to_file.dart';
|
||||
|
||||
import '../screens/DownloadOnlyImportScreen.dart';
|
||||
import '../screens/PkzArchiveScreen.dart';
|
||||
import 'config/TimeOffsetHour.dart';
|
||||
|
||||
/// 默认的图片尺寸
|
||||
|
@ -145,7 +152,8 @@ Future<T?> chooseMapDialog<T>(
|
|||
|
||||
/// 输入对话框1
|
||||
|
||||
var _controller = TextEditingController.fromValue(const TextEditingValue(text: ''));
|
||||
var _controller =
|
||||
TextEditingController.fromValue(const TextEditingValue(text: ''));
|
||||
|
||||
Future<String?> displayTextInputDialog(BuildContext context,
|
||||
{String? title,
|
||||
|
@ -285,3 +293,26 @@ Future<String?> inputString(BuildContext context, String title,
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
StreamSubscription<String?> linkSubscript(BuildContext context) {
|
||||
return linkStream.listen((uri) async {
|
||||
if (uri == null) return;
|
||||
if (RegExp(r"^.*\.pkz$").allMatches(uri).isNotEmpty) {
|
||||
File file = await toFile(uri);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: file.path),
|
||||
),
|
||||
);
|
||||
} else if (RegExp(r"^.*\.((pki)|(zip))$").allMatches(uri).isNotEmpty) {
|
||||
File file = await toFile(uri);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
DownloadOnlyImportScreen(path: file.path),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -547,6 +547,15 @@ class Method {
|
|||
});
|
||||
}
|
||||
|
||||
/// 导出下载的漫画到pki
|
||||
Future<dynamic> exportComicDownloadToPki(String comicId, String dir, String name) {
|
||||
return _flatInvoke("exportComicDownloadToPki", {
|
||||
"comicId": comicId,
|
||||
"dir": dir,
|
||||
"name": name,
|
||||
});
|
||||
}
|
||||
|
||||
/// 导出下载的图片到HTML+JPG
|
||||
Future<dynamic> exportComicDownloadToJPG(
|
||||
String comicId,
|
||||
|
@ -588,6 +597,11 @@ class Method {
|
|||
return _flatInvoke("importComicDownload", zipPath);
|
||||
}
|
||||
|
||||
/// 从pki导入漫画
|
||||
Future<dynamic> importComicDownloadPki(String zipPath) {
|
||||
return _flatInvoke("importComicDownloadPki", zipPath);
|
||||
}
|
||||
|
||||
/// 从网络接收漫画
|
||||
Future<dynamic> importComicDownloadUsingSocket(String addr) {
|
||||
return _flatInvoke("importComicDownloadUsingSocket", addr);
|
||||
|
|
|
@ -36,19 +36,7 @@ class _AccountScreenState extends State<AccountScreen> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
// todo 不必要cancel 随机监听就好了, APP关闭时销毁, 考虑移动到APP里
|
||||
_linkSubscription = linkStream.listen((uri) async {
|
||||
if (uri == null) return;
|
||||
RegExp regExp = RegExp(r"^.*\.pkz$");
|
||||
final matches = regExp.allMatches(uri.toString());
|
||||
if (matches.isNotEmpty) {
|
||||
File file = await toFile(uri.toString());
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: file.path),
|
||||
));
|
||||
}
|
||||
});
|
||||
_linkSubscription = linkSubscript(context);
|
||||
|
||||
_loadProperties();
|
||||
super.initState();
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:pikapika/screens/components/Badge.dart';
|
|||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:uri_to_file/uri_to_file.dart';
|
||||
|
||||
import '../basic/Common.dart';
|
||||
import 'CategoriesScreen.dart';
|
||||
import 'PkzArchiveScreen.dart';
|
||||
import 'SpaceScreen.dart';
|
||||
|
@ -25,20 +26,7 @@ class _AppScreenState extends State<AppScreen> {
|
|||
@override
|
||||
void initState() {
|
||||
versionEvent.subscribe(_onVersion);
|
||||
// todo 不必要cancel 随机监听就好了, APP关闭时销毁, 考虑移动到APP里
|
||||
_linkSubscription = linkStream.listen((uri) async {
|
||||
if (uri == null) return;
|
||||
RegExp regExp = RegExp(r"^.*\.pkz$");
|
||||
final matches = regExp.allMatches(uri);
|
||||
if (matches.isNotEmpty) {
|
||||
File file = await toFile(uri);
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: file.path),
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
_linkSubscription = linkSubscript(context);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ class _DownloadExportToFileScreenState
|
|||
},
|
||||
child: _buildButtonInner('传输到其他设备'),
|
||||
),
|
||||
Container(height: 10),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -238,6 +239,59 @@ class _DownloadExportToFileScreenState
|
|||
));
|
||||
widgets.add(Container(height: 10));
|
||||
/////////////////////
|
||||
/////////////////////
|
||||
widgets.add(MaterialButton(
|
||||
onPressed: () async {
|
||||
late String? path;
|
||||
try {
|
||||
path = await chooseFolder(context);
|
||||
} catch (e) {
|
||||
defaultToast(context, "$e");
|
||||
return;
|
||||
}
|
||||
var name = "";
|
||||
if (currentExportRename()) {
|
||||
var rename = await inputString(
|
||||
context,
|
||||
"请输入保存后的名称",
|
||||
defaultValue: _task.title,
|
||||
);
|
||||
if (rename != null && rename.isNotEmpty) {
|
||||
name = rename;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
print("path $path");
|
||||
if (path != null) {
|
||||
try {
|
||||
setState(() {
|
||||
exporting = true;
|
||||
});
|
||||
await method.exportComicDownloadToPki(
|
||||
widget.comicId,
|
||||
path,
|
||||
name,
|
||||
);
|
||||
setState(() {
|
||||
exportResult = "导出成功";
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
exportResult = "导出失败 $e";
|
||||
});
|
||||
} finally {
|
||||
setState(() {
|
||||
exporting = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
child:
|
||||
_buildButtonInner('导出到xxx.pki\n(只支持导入, 不支持直接阅读)\n(可以躲避网盘或者聊天软件的扫描)\n(后期版本可能支持直接阅读)'),
|
||||
));
|
||||
widgets.add(Container(height: 10));
|
||||
/////////////////////
|
||||
widgets.add(MaterialButton(
|
||||
onPressed: () async {
|
||||
late String? path;
|
||||
|
|
|
@ -74,7 +74,7 @@ class _DownloadExportingGroupScreenState
|
|||
var rename = await inputString(
|
||||
context,
|
||||
"请输入保存后的名称",
|
||||
defaultValue: "${DateTime.now().millisecondsSinceEpoch}.pkz",
|
||||
defaultValue: "${DateTime.now().millisecondsSinceEpoch}",
|
||||
);
|
||||
if (rename != null && rename.isNotEmpty) {
|
||||
name = rename;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:filesystem_picker/filesystem_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pikapika/basic/Channels.dart';
|
||||
import 'package:pikapika/basic/Common.dart';
|
||||
|
@ -91,29 +92,46 @@ class _DownloadImportScreenState extends State<DownloadImportScreen> {
|
|||
defaultToast(context, "$e");
|
||||
return;
|
||||
}
|
||||
String? path;
|
||||
if (Platform.isAndroid) {
|
||||
path = await FilesystemPicker.open(
|
||||
title: 'Open file',
|
||||
context: context,
|
||||
rootDirectory: Directory(chooseRoot),
|
||||
fsType: FilesystemType.file,
|
||||
folderIconColor: Colors.teal,
|
||||
allowedExtensions: ['.pkz', '.zip', '.pki'],
|
||||
fileTileSelectMode: FileTileSelectMode.wholeTile,
|
||||
);
|
||||
}else{
|
||||
var ls = await FilePicker.platform.pickFiles(
|
||||
dialogTitle: '选择要导入的文件',
|
||||
allowMultiple: false,
|
||||
initialDirectory: chooseRoot,
|
||||
type: FileType.custom,
|
||||
allowedExtensions: ['pkz', 'zip'],
|
||||
allowedExtensions: ['pkz', 'zip', 'pki'],
|
||||
allowCompression: false,
|
||||
);
|
||||
String? path = ls != null && ls.count > 0 ? ls.paths[0] : null;
|
||||
path = ls != null && ls.count > 0 ? ls.paths[0] : null;
|
||||
}
|
||||
if (path != null) {
|
||||
if (path.endsWith(".pkz")) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: path),
|
||||
PkzArchiveScreen(pkzPath: path!),
|
||||
),
|
||||
);
|
||||
} else if (path.endsWith(".zip")) {
|
||||
} else if (path.endsWith(".zip") || path.endsWith(".pki")) {
|
||||
try {
|
||||
setState(() {
|
||||
_importing = true;
|
||||
});
|
||||
if(path.endsWith(".zip")){
|
||||
await method.importComicDownload(path);
|
||||
} else if(path.endsWith(".pki")){
|
||||
await method.importComicDownloadPki(path);
|
||||
}
|
||||
setState(() {
|
||||
_importMessage = "导入成功";
|
||||
});
|
||||
|
@ -130,7 +148,7 @@ class _DownloadImportScreenState extends State<DownloadImportScreen> {
|
|||
}
|
||||
},
|
||||
child: const Text(
|
||||
'选择zip文件进行导入\n选择pkz文件进行阅读',
|
||||
'选择zip文件进行导入\n选择pki文件进行导入\n选择pkz文件进行阅读',
|
||||
style: TextStyle(),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:pikapika/basic/Common.dart';
|
||||
|
||||
import '../basic/Channels.dart';
|
||||
import '../basic/Method.dart';
|
||||
import 'components/ContentLoading.dart';
|
||||
|
||||
class DownloadOnlyImportScreen extends StatefulWidget {
|
||||
final bool holdPkz;
|
||||
final String path;
|
||||
|
||||
const DownloadOnlyImportScreen({
|
||||
Key? key,
|
||||
required this.path,
|
||||
this.holdPkz = false,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _DownloadOnlyImportScreenState();
|
||||
}
|
||||
|
||||
class _DownloadOnlyImportScreenState extends State<DownloadOnlyImportScreen> {
|
||||
bool importing = false;
|
||||
bool imported = false;
|
||||
bool importFail = false;
|
||||
dynamic e;
|
||||
String importMessage = "正在导入";
|
||||
StreamSubscription<String?>? _linkSubscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (widget.holdPkz) {
|
||||
_linkSubscription = linkSubscript(context);
|
||||
}
|
||||
registerEvent(_onMessageChange, "EXPORT");
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_linkSubscription?.cancel();
|
||||
unregisterEvent(_onMessageChange);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onMessageChange(event) {
|
||||
setState(() {
|
||||
importMessage = event;
|
||||
});
|
||||
}
|
||||
|
||||
Widget _body() {
|
||||
if (importing) {
|
||||
return ContentLoading(label: importMessage);
|
||||
}
|
||||
if (importFail) {
|
||||
return Center(child: Text("导入失败\n$e"));
|
||||
}
|
||||
if (imported) {
|
||||
return const Center(child: Text("导入成功"));
|
||||
}
|
||||
return Center(
|
||||
child: MaterialButton(
|
||||
onPressed: _import,
|
||||
child: Text("点击导入文件\n${p.basename(widget.path)}"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_import() async {
|
||||
try {
|
||||
setState(() {
|
||||
importing = true;
|
||||
});
|
||||
if (widget.path.endsWith(".zip")) {
|
||||
await method.importComicDownload(widget.path);
|
||||
} else if (widget.path.endsWith(".pki")) {
|
||||
await method.importComicDownloadPki(widget.path);
|
||||
}
|
||||
imported = true;
|
||||
} catch (err) {
|
||||
e = err;
|
||||
importFail = true;
|
||||
} finally {
|
||||
setState(() {
|
||||
importing = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("导入"),
|
||||
),
|
||||
body: _body(),
|
||||
),
|
||||
onWillPop: () async {
|
||||
if (importing) {
|
||||
defaultToast(context, "导入中, 请稍后");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@ import 'package:uri_to_file/uri_to_file.dart';
|
|||
import '../basic/config/ExportRename.dart';
|
||||
import 'AccountScreen.dart';
|
||||
import 'AppScreen.dart';
|
||||
import 'DownloadOnlyImportScreen.dart';
|
||||
|
||||
// 初始化界面
|
||||
class InitScreen extends StatefulWidget {
|
||||
|
@ -106,15 +107,22 @@ class _InitScreenState extends State<InitScreen> {
|
|||
}
|
||||
}
|
||||
if (initUrl != null) {
|
||||
RegExp regExp = RegExp(r"^.*\.pkz$");
|
||||
final matches = regExp.allMatches(initUrl!);
|
||||
if (matches.isNotEmpty) {
|
||||
if (RegExp(r"^.*\.pkz$").allMatches(initUrl!).isNotEmpty) {
|
||||
File file = await toFile(initUrl!);
|
||||
Navigator.of(context).pushReplacement(MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: file.path, holdPkz: true),
|
||||
));
|
||||
return;
|
||||
} else if (RegExp(r"^.*\.((pki)|(zip))$").allMatches(initUrl!).isNotEmpty) {
|
||||
File file = await toFile(initUrl!);
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
DownloadOnlyImportScreen(path: file.path, holdPkz: true),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:pikapika/screens/components/PkzComicInfoCard.dart';
|
|||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:uri_to_file/uri_to_file.dart';
|
||||
|
||||
import '../basic/Common.dart';
|
||||
import '../basic/Navigator.dart';
|
||||
import 'PkzComicInfoScreen.dart';
|
||||
|
||||
|
@ -38,21 +39,7 @@ class _PkzArchiveScreenState extends State<PkzArchiveScreen> with RouteAware {
|
|||
@override
|
||||
void initState() {
|
||||
if (widget.holdPkz) {
|
||||
// todo 不必要cancel 随机监听就好了, APP关闭时销毁, 考虑移动到APP里
|
||||
_linkSubscription = linkStream.listen((uri) async {
|
||||
if(uri == null) return;
|
||||
RegExp regExp = RegExp(r"^.*\.pkz$");
|
||||
final matches = regExp.allMatches(uri);
|
||||
if (matches.isNotEmpty) {
|
||||
File file = await toFile(uri);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: file.path),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
_linkSubscription = linkSubscript(context);
|
||||
}
|
||||
_fileName = p.basename(widget.pkzPath);
|
||||
_future = _load();
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:pikapika/screens/PkzReaderScreen.dart';
|
|||
import 'package:uni_links/uni_links.dart';
|
||||
import 'package:uri_to_file/uri_to_file.dart';
|
||||
|
||||
import '../basic/Common.dart';
|
||||
import '../basic/Navigator.dart';
|
||||
import 'PkzArchiveScreen.dart';
|
||||
import 'components/PkzComicInfoCard.dart';
|
||||
|
@ -37,19 +38,7 @@ class _PkzComicInfoScreenState extends State<PkzComicInfoScreen>
|
|||
@override
|
||||
void initState() {
|
||||
if (widget.holdPkz) {
|
||||
// todo 不必要cancel 随机监听就好了, APP关闭时销毁, 考虑移动到APP里
|
||||
_linkSubscription = linkStream.listen((uri) async {
|
||||
if (uri == null) return;
|
||||
RegExp regExp = RegExp(r"^.*\.pkz$");
|
||||
final matches = regExp.allMatches(uri);
|
||||
if (matches.isNotEmpty) {
|
||||
File file = await toFile(uri);
|
||||
Navigator.of(context).push(MaterialPageRoute(
|
||||
builder: (BuildContext context) =>
|
||||
PkzArchiveScreen(pkzPath: file.path),
|
||||
));
|
||||
}
|
||||
});
|
||||
_linkSubscription = linkSubscript(context);
|
||||
}
|
||||
_load();
|
||||
super.initState();
|
||||
|
|
|
@ -70,7 +70,13 @@ class SettingsScreen extends StatelessWidget {
|
|||
const Divider(),
|
||||
const NetworkSetting(),
|
||||
const Divider(),
|
||||
shadowCategoriesModeSetting(),
|
||||
shadowCategoriesSetting(),
|
||||
qualitySetting(),
|
||||
const Divider(),
|
||||
pagerActionSetting(),
|
||||
contentFailedReloadActionSetting(),
|
||||
const Divider(),
|
||||
readerTypeSetting(),
|
||||
readerDirectionSetting(),
|
||||
readerSliderPositionSetting(),
|
||||
|
@ -80,11 +86,7 @@ class SettingsScreen extends StatelessWidget {
|
|||
keyboardControllerSetting(),
|
||||
noAnimationSetting(),
|
||||
const Divider(),
|
||||
shadowCategoriesModeSetting(),
|
||||
shadowCategoriesSetting(),
|
||||
pagerActionSetting(),
|
||||
fullScreenUISetting(),
|
||||
contentFailedReloadActionSetting(),
|
||||
timeZoneSetting(),
|
||||
const Divider(),
|
||||
autoCleanSecSetting(),
|
||||
|
|
|
@ -120,6 +120,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.6.1"
|
||||
filesystem_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: filesystem_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
|
|
|
@ -50,6 +50,7 @@ dependencies:
|
|||
path: ^1.8.0
|
||||
uri_to_file: ^0.2.0
|
||||
uni_links: ^0.5.1
|
||||
filesystem_picker: ^2.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
|
||||
cd "$( cd "$( dirname "$0" )" && pwd )/.."
|
||||
|
||||
cd go/mobile
|
||||
|
||||
gomobile bind -target=android/arm64 -o lib/Mobile.aar ./
|
|
@ -1,4 +1,4 @@
|
|||
# 编译所有架构的依赖
|
||||
|
||||
|
||||
cd "$( cd "$( dirname "$0" )" && pwd )/.."
|
||||
|
||||
|
|
Loading…
Reference in New Issue