Support pki

This commit is contained in:
niuhuan 2022-07-01 13:39:08 +08:00
parent a246a3d423
commit 03f41bab0b
18 changed files with 310 additions and 80 deletions

View File

@ -52,6 +52,7 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:mimeType="*/*" android:mimeType="*/*"
android:pathPattern=".*\\.pkz" android:pathPattern=".*\\.pkz"
@ -60,6 +61,25 @@
android:mimeType="*/*" android:mimeType="*/*"
android:pathPattern=".*\\.pkz" android:pathPattern=".*\\.pkz"
android:scheme="file" /> 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> </intent-filter>
</activity> </activity>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.

View File

@ -40,10 +40,14 @@
<key>public.filename-extension</key> <key>public.filename-extension</key>
<array> <array>
<string>pkz</string> <string>pkz</string>
<string>pki</string>
<string>zip</string>
</array> </array>
<key>public.mime-type</key> <key>public.mime-type</key>
<array> <array>
<string>text/vnd.niuhuan.pkz</string> <string>text/vnd.niuhuan.pkz</string>
<string>text/vnd.niuhuan.pki</string>
<string>text/vnd.niuhuan.zip</string>
</array> </array>
</dict> </dict>
</dict> </dict>

View File

@ -1,6 +1,13 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.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'; import 'config/TimeOffsetHour.dart';
/// ///
@ -145,7 +152,8 @@ Future<T?> chooseMapDialog<T>(
/// 1 /// 1
var _controller = TextEditingController.fromValue(const TextEditingValue(text: '')); var _controller =
TextEditingController.fromValue(const TextEditingValue(text: ''));
Future<String?> displayTextInputDialog(BuildContext context, Future<String?> displayTextInputDialog(BuildContext context,
{String? title, {String? title,
@ -259,7 +267,7 @@ Future<String?> inputString(BuildContext context, String title,
Text(title), Text(title),
TextField( TextField(
controller: _textEditController, controller: _textEditController,
decoration: InputDecoration( decoration: InputDecoration(
labelText: hint, labelText: hint,
), ),
), ),
@ -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),
),
);
}
});
}

View File

@ -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 /// HTML+JPG
Future<dynamic> exportComicDownloadToJPG( Future<dynamic> exportComicDownloadToJPG(
String comicId, String comicId,
@ -588,6 +597,11 @@ class Method {
return _flatInvoke("importComicDownload", zipPath); return _flatInvoke("importComicDownload", zipPath);
} }
/// pki导入漫画
Future<dynamic> importComicDownloadPki(String zipPath) {
return _flatInvoke("importComicDownloadPki", zipPath);
}
/// ///
Future<dynamic> importComicDownloadUsingSocket(String addr) { Future<dynamic> importComicDownloadUsingSocket(String addr) {
return _flatInvoke("importComicDownloadUsingSocket", addr); return _flatInvoke("importComicDownloadUsingSocket", addr);

View File

@ -36,19 +36,7 @@ class _AccountScreenState extends State<AccountScreen> {
@override @override
void initState() { void initState() {
// todo cancel , APP关闭时销毁, APP里 _linkSubscription = linkSubscript(context);
_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),
));
}
});
_loadProperties(); _loadProperties();
super.initState(); super.initState();

View File

@ -7,6 +7,7 @@ import 'package:pikapika/screens/components/Badge.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:uri_to_file/uri_to_file.dart'; import 'package:uri_to_file/uri_to_file.dart';
import '../basic/Common.dart';
import 'CategoriesScreen.dart'; import 'CategoriesScreen.dart';
import 'PkzArchiveScreen.dart'; import 'PkzArchiveScreen.dart';
import 'SpaceScreen.dart'; import 'SpaceScreen.dart';
@ -25,20 +26,7 @@ class _AppScreenState extends State<AppScreen> {
@override @override
void initState() { void initState() {
versionEvent.subscribe(_onVersion); versionEvent.subscribe(_onVersion);
// todo cancel , APP关闭时销毁, APP里 _linkSubscription = linkSubscript(context);
_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),
));
}
});
super.initState(); super.initState();
} }

View File

@ -122,6 +122,7 @@ class _DownloadExportToFileScreenState
}, },
child: _buildButtonInner('传输到其他设备'), child: _buildButtonInner('传输到其他设备'),
), ),
Container(height: 10),
], ],
); );
}, },
@ -234,7 +235,60 @@ class _DownloadExportToFileScreenState
} }
}, },
child: child:
_buildButtonInner('导出到xxx.pkz\n(可直接打开观看的格式,不支持导入)\n(可以躲避网盘或者聊天软件的扫描)'), _buildButtonInner('导出到xxx.pkz\n(可直接打开观看的格式,不支持导入)\n(可以躲避网盘或者聊天软件的扫描)'),
));
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(Container(height: 10));
///////////////////// /////////////////////

View File

@ -74,7 +74,7 @@ class _DownloadExportingGroupScreenState
var rename = await inputString( var rename = await inputString(
context, context,
"请输入保存后的名称", "请输入保存后的名称",
defaultValue: "${DateTime.now().millisecondsSinceEpoch}.pkz", defaultValue: "${DateTime.now().millisecondsSinceEpoch}",
); );
if (rename != null && rename.isNotEmpty) { if (rename != null && rename.isNotEmpty) {
name = rename; name = rename;

View File

@ -1,6 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:filesystem_picker/filesystem_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pikapika/basic/Channels.dart'; import 'package:pikapika/basic/Channels.dart';
import 'package:pikapika/basic/Common.dart'; import 'package:pikapika/basic/Common.dart';
@ -91,29 +92,46 @@ class _DownloadImportScreenState extends State<DownloadImportScreen> {
defaultToast(context, "$e"); defaultToast(context, "$e");
return; return;
} }
var ls = await FilePicker.platform.pickFiles( String? path;
dialogTitle: '选择要导入的文件', if (Platform.isAndroid) {
allowMultiple: false, path = await FilesystemPicker.open(
initialDirectory: chooseRoot, title: 'Open file',
type: FileType.custom, context: context,
allowedExtensions: ['pkz', 'zip'], rootDirectory: Directory(chooseRoot),
allowCompression: false, fsType: FilesystemType.file,
); folderIconColor: Colors.teal,
String? path = ls != null && ls.count > 0 ? ls.paths[0] : null; 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', 'pki'],
allowCompression: false,
);
path = ls != null && ls.count > 0 ? ls.paths[0] : null;
}
if (path != null) { if (path != null) {
if (path.endsWith(".pkz")) { if (path.endsWith(".pkz")) {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (BuildContext context) => builder: (BuildContext context) =>
PkzArchiveScreen(pkzPath: path), PkzArchiveScreen(pkzPath: path!),
), ),
); );
} else if (path.endsWith(".zip")) { } else if (path.endsWith(".zip") || path.endsWith(".pki")) {
try { try {
setState(() { setState(() {
_importing = true; _importing = true;
}); });
await method.importComicDownload(path); if(path.endsWith(".zip")){
await method.importComicDownload(path);
} else if(path.endsWith(".pki")){
await method.importComicDownloadPki(path);
}
setState(() { setState(() {
_importMessage = "导入成功"; _importMessage = "导入成功";
}); });
@ -130,7 +148,7 @@ class _DownloadImportScreenState extends State<DownloadImportScreen> {
} }
}, },
child: const Text( child: const Text(
'选择zip文件进行导入\n选择pkz文件进行阅读', '选择zip文件进行导入\n选择pki文件进行导入\n选择pkz文件进行阅读',
style: TextStyle(), style: TextStyle(),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),

View File

@ -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;
},
);
}
}

View File

@ -39,6 +39,7 @@ import 'package:uri_to_file/uri_to_file.dart';
import '../basic/config/ExportRename.dart'; import '../basic/config/ExportRename.dart';
import 'AccountScreen.dart'; import 'AccountScreen.dart';
import 'AppScreen.dart'; import 'AppScreen.dart';
import 'DownloadOnlyImportScreen.dart';
// //
class InitScreen extends StatefulWidget { class InitScreen extends StatefulWidget {
@ -106,15 +107,22 @@ class _InitScreenState extends State<InitScreen> {
} }
} }
if (initUrl != null) { if (initUrl != null) {
RegExp regExp = RegExp(r"^.*\.pkz$"); if (RegExp(r"^.*\.pkz$").allMatches(initUrl!).isNotEmpty) {
final matches = regExp.allMatches(initUrl!);
if (matches.isNotEmpty) {
File file = await toFile(initUrl!); File file = await toFile(initUrl!);
Navigator.of(context).pushReplacement(MaterialPageRoute( Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (BuildContext context) => builder: (BuildContext context) =>
PkzArchiveScreen(pkzPath: file.path, holdPkz: true), PkzArchiveScreen(pkzPath: file.path, holdPkz: true),
)); ));
return; 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;
} }
} }

View File

@ -11,6 +11,7 @@ import 'package:pikapika/screens/components/PkzComicInfoCard.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:uri_to_file/uri_to_file.dart'; import 'package:uri_to_file/uri_to_file.dart';
import '../basic/Common.dart';
import '../basic/Navigator.dart'; import '../basic/Navigator.dart';
import 'PkzComicInfoScreen.dart'; import 'PkzComicInfoScreen.dart';
@ -38,21 +39,7 @@ class _PkzArchiveScreenState extends State<PkzArchiveScreen> with RouteAware {
@override @override
void initState() { void initState() {
if (widget.holdPkz) { if (widget.holdPkz) {
// todo cancel , APP关闭时销毁, APP里 _linkSubscription = linkSubscript(context);
_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),
),
);
}
});
} }
_fileName = p.basename(widget.pkzPath); _fileName = p.basename(widget.pkzPath);
_future = _load(); _future = _load();

View File

@ -9,6 +9,7 @@ import 'package:pikapika/screens/PkzReaderScreen.dart';
import 'package:uni_links/uni_links.dart'; import 'package:uni_links/uni_links.dart';
import 'package:uri_to_file/uri_to_file.dart'; import 'package:uri_to_file/uri_to_file.dart';
import '../basic/Common.dart';
import '../basic/Navigator.dart'; import '../basic/Navigator.dart';
import 'PkzArchiveScreen.dart'; import 'PkzArchiveScreen.dart';
import 'components/PkzComicInfoCard.dart'; import 'components/PkzComicInfoCard.dart';
@ -37,19 +38,7 @@ class _PkzComicInfoScreenState extends State<PkzComicInfoScreen>
@override @override
void initState() { void initState() {
if (widget.holdPkz) { if (widget.holdPkz) {
// todo cancel , APP关闭时销毁, APP里 _linkSubscription = linkSubscript(context);
_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),
));
}
});
} }
_load(); _load();
super.initState(); super.initState();

View File

@ -70,7 +70,13 @@ class SettingsScreen extends StatelessWidget {
const Divider(), const Divider(),
const NetworkSetting(), const NetworkSetting(),
const Divider(), const Divider(),
shadowCategoriesModeSetting(),
shadowCategoriesSetting(),
qualitySetting(), qualitySetting(),
const Divider(),
pagerActionSetting(),
contentFailedReloadActionSetting(),
const Divider(),
readerTypeSetting(), readerTypeSetting(),
readerDirectionSetting(), readerDirectionSetting(),
readerSliderPositionSetting(), readerSliderPositionSetting(),
@ -80,11 +86,7 @@ class SettingsScreen extends StatelessWidget {
keyboardControllerSetting(), keyboardControllerSetting(),
noAnimationSetting(), noAnimationSetting(),
const Divider(), const Divider(),
shadowCategoriesModeSetting(),
shadowCategoriesSetting(),
pagerActionSetting(),
fullScreenUISetting(), fullScreenUISetting(),
contentFailedReloadActionSetting(),
timeZoneSetting(), timeZoneSetting(),
const Divider(), const Divider(),
autoCleanSecSetting(), autoCleanSecSetting(),

View File

@ -120,6 +120,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.6.1" 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: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter

View File

@ -50,6 +50,7 @@ dependencies:
path: ^1.8.0 path: ^1.8.0
uri_to_file: ^0.2.0 uri_to_file: ^0.2.0
uni_links: ^0.5.1 uni_links: ^0.5.1
filesystem_picker: ^2.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -0,0 +1,7 @@
cd "$( cd "$( dirname "$0" )" && pwd )/.."
cd go/mobile
gomobile bind -target=android/arm64 -o lib/Mobile.aar ./

View File

@ -1,4 +1,4 @@
# 编译所有架构的依赖
cd "$( cd "$( dirname "$0" )" && pwd )/.." cd "$( cd "$( dirname "$0" )" && pwd )/.."