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" />
<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.

View File

@ -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>

View File

@ -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,
@ -259,7 +267,7 @@ Future<String?> inputString(BuildContext context, String title,
Text(title),
TextField(
controller: _textEditController,
decoration: InputDecoration(
decoration: InputDecoration(
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
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);

View File

@ -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();

View File

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

View File

@ -122,6 +122,7 @@ class _DownloadExportToFileScreenState
},
child: _buildButtonInner('传输到其他设备'),
),
Container(height: 10),
],
);
},
@ -234,7 +235,60 @@ class _DownloadExportToFileScreenState
}
},
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));
/////////////////////

View File

@ -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;

View File

@ -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;
}
var ls = await FilePicker.platform.pickFiles(
dialogTitle: '选择要导入的文件',
allowMultiple: false,
initialDirectory: chooseRoot,
type: FileType.custom,
allowedExtensions: ['pkz', 'zip'],
allowCompression: false,
);
String? path = ls != null && ls.count > 0 ? ls.paths[0] : null;
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', 'pki'],
allowCompression: false,
);
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;
});
await method.importComicDownload(path);
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,
),

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 '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;
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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(),

View File

@ -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

View File

@ -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:

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 )/.."