diff --git a/README.md b/README.md
index b29f531..71d94b0 100644
--- a/README.md
+++ b/README.md
@@ -89,21 +89,11 @@ VPN->代理->分流, 这三个功能如果同时设置, 您会在您手机的VPN
## 请您遵守使用规则
-本文中提到的本软件拓展包括但是不限于以下内容
+软件副本分发以及代码使用规则
-- 使用本软件进行继续开发形成的软件。
-- 引入本软件部分内容为依赖/使用本软件内代码的同时包含本软件内一致内容或功能。
-- 直接对本软件进行打包发布
-
-软件副本分发以及代码使用规则规则
-
-- 本软件仅供学习交流使用, 本软件或本软件的拓展, 个人或企业不可用于商业用途, 不可上架任何商店。
-- 本软件的拓展在未经允许的情况下可以自用但不允许释放任何releases。
+- 本软件的代码在未经允许的情况下可以自用但不允许释放任何releases, 个人或企业不可用于商业用途, 不可上架任何商店。。
- 不要在任何其他 **二次元软件** 的 **聊天社区** 或 **开发社区** 内, 发布有关本软件的链接或信息, 对于观点不同产生的分歧作者不站队任何立场。
-- 不要发送本软件安装包到 **任何社区内** , 不要将APK/IPA/ZIP/DMG发送包括任何聊天软件内的群聊功能。 分享本软件时, 在社区中使用Github中提供的Releases页面的链接, 或使用私聊窗口发送。
-
-源代码使用规则
-
+- 不要发送本软件安装包到 **任何社区内** , 不要将APK/IPA/ZIP/DMG发送包括任何聊天软件内的群聊功能。 请使用Github中提供的Releases页面的链接。
- 对本仓库的fork需要保留本仓库的链接, 以引导用户在主要仓库进行讨论。
责任声明
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 1e6b4a7..6cac205 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
diff --git a/ci/version.info.txt b/ci/version.info.txt
index 3bb7d4e..ba3c04f 100644
--- a/ci/version.info.txt
+++ b/ci/version.info.txt
@@ -1,3 +1,6 @@
v1.7.2
- [x] 🐛 修复安卓13导入导出的问题
- [x] 🐛 修复测速不好用的问题
+- [x] ♻️ 梳理一些权限
+- [x] ✨ 增加批量下载功能
+- [x] ✨ 增加PAT入会发电
diff --git a/lib/basic/Common.dart b/lib/basic/Common.dart
index f8183bc..eb3fe86 100644
--- a/lib/basic/Common.dart
+++ b/lib/basic/Common.dart
@@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
+import 'package:pikapika/screens/AccessKeyReplaceScreen.dart';
import 'package:uni_links/uni_links.dart';
import 'package:uri_to_file/uri_to_file.dart';
@@ -300,7 +301,17 @@ StreamSubscription linkSubscript(BuildContext context) {
return linkStream.listen((uri) async {
if (uri == null) return;
var parsed = Uri.parse(uri);
- if (RegExp(r"^pika://comic/([0-9A-z]+)/$").allMatches(uri).isNotEmpty) {
+ if (RegExp(r"^pika://access_key/([0-9A-z:\-]+)/$").allMatches(uri).isNotEmpty) {
+ String accessKey = RegExp(r"^pika://access_key/([0-9A-z:\-]+)/$")
+ .allMatches(uri)
+ .first
+ .group(1)!;
+ Navigator.of(context).push(
+ mixRoute(
+ builder: (BuildContext context) => AccessKeyReplaceScreen(accessKey: accessKey),
+ ),
+ );
+ } else if (RegExp(r"^pika://comic/([0-9A-z]+)/$").allMatches(uri).isNotEmpty) {
String comicId = RegExp(r"^pika://comic/([0-9A-z]+)/$")
.allMatches(uri)
.first
diff --git a/lib/basic/Cross.dart b/lib/basic/Cross.dart
index c13859a..5b76bd2 100644
--- a/lib/basic/Cross.dart
+++ b/lib/basic/Cross.dart
@@ -6,6 +6,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:pikapika/basic/Common.dart';
+import 'package:pikapika/basic/config/Platform.dart';
import 'package:url_launcher/url_launcher.dart';
import 'Method.dart';
@@ -68,8 +69,13 @@ Future saveImageQuiet(String path, BuildContext context) async {
}
Future _saveImageAndroid(String path, BuildContext context) async {
- var p = await Permission.storage.request();
- if (!p.isGranted) {
+ late bool g;
+ if (androidVersion < 30) {
+ g = await Permission.storage.request().isGranted;
+ }else{
+ g = await Permission.manageExternalStorage.request().isGranted;
+ }
+ if (!g) {
return;
}
return method.androidSaveFileToImage(path);
diff --git a/lib/basic/Entities.dart b/lib/basic/Entities.dart
index a176358..5017479 100644
--- a/lib/basic/Entities.dart
+++ b/lib/basic/Entities.dart
@@ -1065,6 +1065,7 @@ class ProInfoPat {
required this.reBind,
required this.errorType,
required this.errorMsg,
+ required this.accessKey,
});
late final bool isPro;
late final String patId;
@@ -1073,6 +1074,7 @@ class ProInfoPat {
late final int reBind;
late final int errorType;
late final String errorMsg;
+ late final String accessKey;
ProInfoPat.fromJson(Map json){
isPro = json['is_pro'];
@@ -1082,6 +1084,7 @@ class ProInfoPat {
reBind = json['re_bind'];
errorType = json['error_type'];
errorMsg = json['error_msg'];
+ accessKey = json['access_key'];
}
Map toJson() {
@@ -1093,6 +1096,7 @@ class ProInfoPat {
_data['re_bind'] = reBind;
_data['error_type'] = errorType;
_data['error_msg'] = errorMsg;
+ _data['access_key'] = accessKey;
return _data;
}
}
diff --git a/lib/basic/Method.dart b/lib/basic/Method.dart
index 0b0d0c1..635d2f0 100644
--- a/lib/basic/Method.dart
+++ b/lib/basic/Method.dart
@@ -1013,4 +1013,20 @@ class Method {
Future downloadAll(List comicIds) {
return _flatInvoke("downloadAll", comicIds);
}
+
+ Future setPatAccessKey(String accessKey) {
+ return _flatInvoke("setPatAccessKey", accessKey);
+ }
+
+ Future reloadPatAccount() {
+ return _flatInvoke("reloadPatAccount", "");
+ }
+
+ Future bindThisAccount() {
+ return _flatInvoke("bindThisAccount", "");
+ }
+
+ Future clearPat() {
+ return _flatInvoke("clearPat", "");
+ }
}
diff --git a/lib/basic/config/ChooserRoot.dart b/lib/basic/config/ChooserRoot.dart
index c7b75e4..d40e1b4 100644
--- a/lib/basic/config/ChooserRoot.dart
+++ b/lib/basic/config/ChooserRoot.dart
@@ -7,6 +7,7 @@ import 'package:permission_handler/permission_handler.dart';
import '../Common.dart';
import '../Method.dart';
+import 'Platform.dart';
const _propertyName = "chooserRoot";
late String _chooserRoot;
@@ -30,7 +31,13 @@ Future initChooserRoot() async {
Future currentChooserRoot() async {
if (Platform.isAndroid) {
- if (!(await Permission.storage.request()).isGranted) {
+ late bool g;
+ if (androidVersion < 30) {
+ g = await Permission.storage.request().isGranted;
+ }else{
+ g = await Permission.manageExternalStorage.request().isGranted;
+ }
+ if (!g) {
throw Exception("申请权限被拒绝");
}
}
diff --git a/lib/basic/config/ExportPath.dart b/lib/basic/config/ExportPath.dart
index c0c546a..052bcc1 100644
--- a/lib/basic/config/ExportPath.dart
+++ b/lib/basic/config/ExportPath.dart
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import '../Cross.dart';
import '../Method.dart';
+import 'Platform.dart';
const _propertyName = "exportPath";
late String _exportPath;
@@ -35,7 +36,13 @@ Future attachExportPath() async {
path = await method.iosGetDocumentDir();
} else {
if (Platform.isAndroid) {
- if (!(await Permission.storage.request()).isGranted) {
+ late bool g;
+ if (androidVersion < 30) {
+ g = await Permission.storage.request().isGranted;
+ }else{
+ g = await Permission.manageExternalStorage.request().isGranted;
+ }
+ if (!g) {
throw Exception("申请权限被拒绝");
}
}
diff --git a/lib/screens/AccessKeyReplaceScreen.dart b/lib/screens/AccessKeyReplaceScreen.dart
new file mode 100644
index 0000000..c84d65a
--- /dev/null
+++ b/lib/screens/AccessKeyReplaceScreen.dart
@@ -0,0 +1,75 @@
+import 'package:flutter/material.dart';
+import 'package:pikapika/basic/Method.dart';
+import 'package:pikapika/screens/components/ContentLoading.dart';
+
+import '../basic/config/IsPro.dart';
+
+class AccessKeyReplaceScreen extends StatefulWidget {
+ final String accessKey;
+
+ const AccessKeyReplaceScreen({Key? key, required this.accessKey})
+ : super(key: key);
+
+ @override
+ State createState() => _AccessKeyReplaceScreenState();
+}
+
+class _AccessKeyReplaceScreenState extends State {
+ var _loading = false;
+ var _message = "";
+ var _success = false;
+
+ _set() async {
+ setState(() {
+ _loading = true;
+ });
+ try {
+ await method.setPatAccessKey(widget.accessKey);
+ await reloadIsPro();
+ _success = true;
+ } catch (e) {
+ _message = "错误 : $e";
+ } finally {
+ setState(() {
+ _loading = false;
+ });
+ }
+ }
+
+ Widget _content() {
+ if (_loading) {
+ return const ContentLoading(label: "加载中");
+ }
+ if (_success) {
+ return const Text("您的赞助登录成功, 请返回");
+ }
+ return Column(
+ children: [
+ Expanded(child: Container()),
+ Text(widget.accessKey),
+ Text(_message),
+ Container(
+ height: 10,
+ ),
+ MaterialButton(
+ color: Colors.grey,
+ onPressed: _set,
+ child: const Text("确认"),
+ ),
+ Expanded(child: Container()),
+ ],
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text("更换PAT账户"),
+ ),
+ body: Center(
+ child: _content(),
+ ),
+ );
+ }
+}
diff --git a/lib/screens/ComicsScreen.dart b/lib/screens/ComicsScreen.dart
index a40a372..091e414 100644
--- a/lib/screens/ComicsScreen.dart
+++ b/lib/screens/ComicsScreen.dart
@@ -160,7 +160,11 @@ class _ComicsScreenState extends State {
appBar = AppBar(
title: Text(title),
actions: [
- commonPopMenu(context),
+ commonPopMenu(
+ context,
+ setState: setState,
+ comicListController: _comicListController,
+ ),
addressPopMenu(context),
_chooseCategoryAction(),
],
diff --git a/lib/screens/InitScreen.dart b/lib/screens/InitScreen.dart
index ad0fced..9b75a7e 100644
--- a/lib/screens/InitScreen.dart
+++ b/lib/screens/InitScreen.dart
@@ -37,6 +37,7 @@ import 'package:pikapika/basic/config/Version.dart';
import 'package:pikapika/basic/config/VolumeController.dart';
import 'package:pikapika/basic/config/ShadowCategoriesMode.dart';
import 'package:pikapika/basic/config/WillPopNotice.dart';
+import 'package:pikapika/screens/AccessKeyReplaceScreen.dart';
import 'package:pikapika/screens/ComicInfoScreen.dart';
import 'package:pikapika/screens/PkzArchiveScreen.dart';
import 'package:uni_links/uni_links.dart';
@@ -126,15 +127,37 @@ class _InitScreenState extends State {
}
if (initUrl != null) {
var parsed = Uri.parse(initUrl!);
- if (RegExp(r"^pika://comic/([0-9A-z]+)/$").allMatches(initUrl!).isNotEmpty) {
- String comicId = RegExp(r"^pika://comic/([0-9A-z]+)/$").allMatches(initUrl!).first.group(1)!;
+ if (RegExp(r"^pika://access_key/([0-9A-z:\-]+)/$")
+ .allMatches(initUrl!)
+ .isNotEmpty) {
+ String accessKey = RegExp(r"^pika://access_key/([0-9A-z:\-]+)/$")
+ .allMatches(initUrl!)
+ .first
+ .group(1)!;
+ Navigator.of(context).pushReplacement(mixRoute(
+ builder: (BuildContext context) =>
+ AccessKeyReplaceScreen(accessKey: accessKey),
+ ));
+ return;
+ } else if (RegExp(r"^pika://comic/([0-9A-z]+)/$")
+ .allMatches(initUrl!)
+ .isNotEmpty) {
+ String comicId = RegExp(r"^pika://comic/([0-9A-z]+)/$")
+ .allMatches(initUrl!)
+ .first
+ .group(1)!;
Navigator.of(context).pushReplacement(mixRoute(
builder: (BuildContext context) =>
ComicInfoScreen(comicId: comicId, holdPkz: true),
));
return;
- } if (RegExp(r"^https?://pika/comic/([0-9A-z]+)/$").allMatches(initUrl!).isNotEmpty) {
- String comicId = RegExp(r"^https?://pika/comic/([0-9A-z]+)/$").allMatches(initUrl!).first.group(1)!;
+ } else if (RegExp(r"^https?://pika/comic/([0-9A-z]+)/$")
+ .allMatches(initUrl!)
+ .isNotEmpty) {
+ String comicId = RegExp(r"^https?://pika/comic/([0-9A-z]+)/$")
+ .allMatches(initUrl!)
+ .first
+ .group(1)!;
Navigator.of(context).pushReplacement(mixRoute(
builder: (BuildContext context) =>
ComicInfoScreen(comicId: comicId, holdPkz: true),
@@ -147,7 +170,9 @@ class _InitScreenState extends State {
PkzArchiveScreen(pkzPath: file.path, holdPkz: true),
));
return;
- } else if (RegExp(r"^.*\.((pki)|(zip))$").allMatches(parsed.path).isNotEmpty) {
+ } else if (RegExp(r"^.*\.((pki)|(zip))$")
+ .allMatches(parsed.path)
+ .isNotEmpty) {
File file = await toFile(initUrl!);
Navigator.of(context).pushReplacement(
mixRoute(
diff --git a/lib/screens/PkzArchiveScreen.dart b/lib/screens/PkzArchiveScreen.dart
index 935e7ee..c0a31ff 100644
--- a/lib/screens/PkzArchiveScreen.dart
+++ b/lib/screens/PkzArchiveScreen.dart
@@ -14,6 +14,7 @@ import 'package:uri_to_file/uri_to_file.dart';
import '../basic/Common.dart';
import '../basic/Navigator.dart';
import '../basic/config/IconLoading.dart';
+import '../basic/config/Platform.dart';
import 'PkzComicInfoScreen.dart';
class PkzArchiveScreen extends StatefulWidget {
@@ -75,9 +76,16 @@ class _PkzArchiveScreenState extends State with RouteAware {
Future _load() async {
await method.viewPkz(_fileName, widget.pkzPath);
- var p = await Permission.storage.request();
- if (!p.isGranted) {
- throw 'error permission';
+ if (Platform.isAndroid) {
+ late bool g;
+ if (androidVersion < 30) {
+ g = await Permission.storage.request().isGranted;
+ }else{
+ g = await Permission.manageExternalStorage.request().isGranted;
+ }
+ if (!g) {
+ throw 'error permission';
+ }
}
_info = await method.pkzInfo(widget.pkzPath);
if (_info.comics.length == 1) {
diff --git a/lib/screens/ProScreen.dart b/lib/screens/ProScreen.dart
index 71413b2..7821c5d 100644
--- a/lib/screens/ProScreen.dart
+++ b/lib/screens/ProScreen.dart
@@ -1,7 +1,12 @@
+import 'dart:convert';
+
import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
import 'package:pikapika/basic/Common.dart';
import 'package:pikapika/basic/Method.dart';
+import 'package:pikapika/screens/AccessKeyReplaceScreen.dart';
+import '../basic/config/IconLoading.dart';
import '../basic/config/IsPro.dart';
class ProScreen extends StatefulWidget {
@@ -21,9 +26,20 @@ class _ProScreenState extends State {
_username = value;
});
});
+ proEvent.subscribe(_setState);
super.initState();
}
+ @override
+ void dispose() {
+ proEvent.unsubscribe(_setState);
+ super.dispose();
+ }
+
+ _setState(_) {
+ setState(() {});
+ }
+
@override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
@@ -51,43 +67,25 @@ class _ProScreenState extends State {
const Padding(
padding: EdgeInsets.all(20),
child: Text(
- "点击\"我曾经发过电\"进同步发电状态\n"
- "点击\"我刚才发了电\"兑换作者给您的礼物卡\n"
- "去\"关于\"界面找到维护地址用爱发电",
- ),
- ),
- const Divider(),
- const Padding(
- padding: EdgeInsets.all(20),
- child: Text(
- "发电小功能 \n"
- " 多线程下载\n"
- " 批量导入导出\n"
- " 跳页",
+ "去\"关于\"界面找到维护地址可获得发电指引\n\n"
+ "1. \"签到/游戏/兑换\" \n"
+ " (1). \"我曾经发过电\"可同步相应发电状态\n"
+ " (2). \"我刚才发了电\"兑换作者给您的礼物卡\n"
+ "\n"
+ "2. \"PAT入会\"\n"
+ " 🔗将社区账号链接到软件, 同步成员状态, 订阅式发电"
+ "",
),
),
const Divider(),
ListTile(
- title: const Text("签到或礼物卡"),
+ title: const Text("签到/游戏/兑换"),
subtitle: Text(
proInfoAf.isPro
? "发电中 (${DateTime.fromMillisecondsSinceEpoch(1000 * proInfoAf.expire).toString()})"
: "未发电",
),
),
- ...(proInfoPat.patId.isNotEmpty ? [
- ListTile(
- onTap: () {
- managementPat();
- },
- title: const Text("P站支持"),
- subtitle: Text((
- proInfoPat.isPro
- ? "发电中"
- : "未发电") + ("(点击管理)"),
- ),
- ),
- ] : []),
const Divider(),
ListTile(
title: const Text("我曾经发过电"),
@@ -120,12 +118,156 @@ class _ProScreenState extends State {
},
),
const Divider(),
+ ...patPro(),
+ const Divider(),
+ const Padding(
+ padding: EdgeInsets.all(20),
+ child: Text(
+ "发电小功能 \n"
+ " 多线程下载\n"
+ " 批量导入导出\n"
+ " 跳页",
+ ),
+ ),
+ const Divider(),
+ const Divider(),
],
),
);
}
- void managementPat() {
- // todo
+ List patPro() {
+ List widgets = [];
+ if (proInfoPat.accessKey.isNotEmpty) {
+ var text = "密钥 : 已录入";
+ if (proInfoPat.patId.isNotEmpty) {
+ text += "\nPAT账号 : ${proInfoPat.patId}";
+ }
+ if (proInfoPat.bindUid.isNotEmpty) {
+ text += "\n绑定PIKA账号 : ${proInfoPat.bindUid}";
+ }
+ if (proInfoPat.requestDelete > 0) {
+ DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
+ proInfoPat.requestDelete * 1000,
+ isUtc: true,
+ );
+ String formattedDate =
+ DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime.toLocal());
+ text += "\n绑定账号时间 : $formattedDate";
+ }
+ if (proInfoPat.reBind > 0) {
+ DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(
+ proInfoPat.reBind * 1000,
+ isUtc: true,
+ );
+ String formattedDate =
+ DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime.toLocal());
+ text += "\n可以换绑时间 : $formattedDate";
+ }
+ List append = [];
+ if (proInfoPat.bindUid == "") {
+ append.add(const TextSpan(
+ text: "\n(请点击这里绑定到当前账号发电)",
+ style: TextStyle(color: Colors.blue),
+ ));
+ } else if (proInfoPat.bindUid != _username) {
+ append.add(const TextSpan(
+ text: "\n(请点换绑到当前账号发电)",
+ style: TextStyle(color: Colors.red),
+ ));
+ } else if (proInfoPat.isPro == false) {
+ append.add(const TextSpan(
+ text: "\n(未检测到入会, 请到下载页入会)",
+ style: TextStyle(color: Colors.orange),
+ ));
+ } else {
+ append.add(const TextSpan(
+ text: "\n(PAT正常)",
+ style: TextStyle(color: Colors.green),
+ ));
+ }
+ widgets.add(ListTile(
+ onTap: () async {
+ print(jsonEncode(proInfoPat));
+ var choose = await chooseMapDialog(
+ context,
+ {
+ "更新PAT发电状态": 2,
+ "绑定到此账号": 3,
+ "更换PAT密钥": 1,
+ "清除PAT信息": 4,
+ },
+ "请选择",
+ );
+ switch (choose) {
+ case 1:
+ addPatAccount();
+ break;
+ case 2:
+ reloadPatAccount();
+ break;
+ case 3:
+ bindThisAccount();
+ break;
+ case 4:
+ clearPat();
+ break;
+ }
+ },
+ title: const Text("PAT入会"),
+ subtitle: Text.rich(TextSpan(children: [
+ TextSpan(text: text),
+ ...append,
+ ])),
+ ));
+ } else {
+ widgets.add(ListTile(
+ onTap: () {
+ addPatAccount();
+ },
+ title: const Text("PAT入会"),
+ subtitle: const Text("点击绑定"),
+ ));
+ }
+ return widgets;
+ }
+
+ void addPatAccount() async {
+ print(jsonEncode(proInfoPat));
+ String? key = await inputString(context, "请输入授权代码");
+ if (key != null) {
+ await Navigator.of(context)
+ .push(mixRoute(builder: (BuildContext context) {
+ return AccessKeyReplaceScreen(accessKey: key);
+ }));
+ }
+ }
+
+ reloadPatAccount() async {
+ defaultToast(context, "请稍后");
+ try {
+ await method.reloadPatAccount();
+ await reloadIsPro();
+ defaultToast(context, "SUCCESS");
+ } catch (e) {
+ defaultToast(context, "FAIL : $e");
+ } finally {}
+ }
+
+ bindThisAccount() async {
+ defaultToast(context, "请稍后");
+ try {
+ await method.bindThisAccount();
+ await reloadIsPro();
+ defaultToast(context, "SUCCESS");
+ } catch (e) {
+ defaultToast(context, "FAIL : $e");
+ } finally {}
+ }
+
+ clearPat() async {
+ await method.clearPat();
+ await reloadIsPro();
+ defaultToast(context, "Success");
}
}
diff --git a/lib/screens/SearchScreen.dart b/lib/screens/SearchScreen.dart
index b7433c1..4015cf2 100644
--- a/lib/screens/SearchScreen.dart
+++ b/lib/screens/SearchScreen.dart
@@ -8,8 +8,10 @@ import 'package:pikapika/screens/components/RightClickPop.dart';
import '../basic/Entities.dart';
import '../basic/config/Address.dart';
import '../basic/config/IconLoading.dart';
+import 'components/ComicList.dart';
import 'components/ComicPager.dart';
import 'components/Common.dart';
+import 'components/GoDownloadSelect.dart';
// 搜索页面
class SearchScreen extends StatefulWidget {
@@ -27,6 +29,7 @@ class SearchScreen extends StatefulWidget {
}
class _SearchScreenState extends State {
+ late final _comicListController = ComicListController();
late final TextEditingController _textEditController =
TextEditingController(text: widget.keyword);
late final SearchBar _searchBar = SearchBar(
@@ -51,7 +54,11 @@ class _SearchScreenState extends State {
return AppBar(
title: Text("${categoryTitle(widget.category)} ${widget.keyword}"),
actions: [
- commonPopMenu(context),
+ commonPopMenu(
+ context,
+ setState: setState,
+ comicListController: _comicListController,
+ ),
addressPopMenu(context),
_chooseCategoryAction(),
_searchBar.getSearchAction(context),
@@ -66,7 +73,7 @@ class _SearchScreenState extends State {
categoryTitle(null),
...filteredList(
storedCategories,
- (c) => !shadowCategories.contains(c),
+ (c) => !shadowCategories.contains(c),
),
]);
if (category != null) {
@@ -100,7 +107,7 @@ class _SearchScreenState extends State {
}
@override
- Widget build(BuildContext context){
+ Widget build(BuildContext context) {
return rightClickPop(
child: buildScreen(context),
context: context,
@@ -110,7 +117,9 @@ class _SearchScreenState extends State {
Widget buildScreen(BuildContext context) {
return Scaffold(
- appBar: _searchBar.build(context),
+ appBar: _comicListController.selecting
+ ? downAppBar(context, _comicListController, setState)
+ : _searchBar.build(context),
body: ComicPager(
fetchPage: _fetch,
),
diff --git a/lib/screens/components/Common.dart b/lib/screens/components/Common.dart
index b4b926f..0d2b220 100644
--- a/lib/screens/components/Common.dart
+++ b/lib/screens/components/Common.dart
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
+import 'package:pikapika/basic/Common.dart';
import 'package:pikapika/screens/components/ComicList.dart';
import '../../basic/config/IsPro.dart';
@@ -39,9 +40,12 @@ Widget commonPopMenu(
PopupMenuItem(
value: 3,
child: ListTile(
- leading: const Icon(Icons.download),
+ leading: Icon(
+ Icons.download,
+ color: isPro ? null : Colors.grey,
+ ),
title: Text(
- "下载" + (isPro ? "" : "Pro"),
+ "批量下载" + (isPro ? "" : "(发电)"),
style: TextStyle(
color: isPro ? null : Colors.grey,
),
@@ -63,6 +67,10 @@ Widget commonPopMenu(
chooseShadowCategories(context);
break;
case 3:
+ if (!isPro) {
+ defaultToast(context, "请先发电呀");
+ return;
+ }
if (setState != null) {
if (comicListController != null) {
setState(() {
diff --git a/lib/screens/components/GoDownloadSelect.dart b/lib/screens/components/GoDownloadSelect.dart
index dd3cbbd..986136d 100644
--- a/lib/screens/components/GoDownloadSelect.dart
+++ b/lib/screens/components/GoDownloadSelect.dart
@@ -58,13 +58,15 @@ AppBar downAppBar(
MaterialButton(
minWidth: 0,
onPressed: () async {
- // todo
- final list = _comicListController.selected;
+ var list = _comicListController.selected;
if (list.isEmpty) {
defaultToast(context, "请选择漫画");
return;
}
- _comicListController.selecting = false;
+ list = list.toList();
+ setState((){
+ _comicListController.selecting = false;
+ });
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) {
return DownloadComicsScreen(list);
diff --git a/pubspec.lock b/pubspec.lock
index e1add07..318e637 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -13,10 +13,10 @@ packages:
dependency: transitive
description:
name: archive
- sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d
+ sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
url: "https://pub.dev"
source: hosted
- version: "3.3.6"
+ version: "3.3.7"
async:
dependency: transitive
description:
@@ -273,10 +273,10 @@ packages:
dependency: transitive
description:
name: image_picker_ios
- sha256: d4cb8ab04f770dab9d04c7959e5f6d22e8c5280343d425f9344f93832cf58445
+ sha256: a1546ff5861fc15812953d4733b520c3d371cec3d2859a001ff04c46c4d81883
url: "https://pub.dev"
source: hosted
- version: "0.8.7+2"
+ version: "0.8.7+3"
image_picker_platform_interface:
dependency: transitive
description:
@@ -286,7 +286,7 @@ packages:
source: hosted
version: "2.6.3"
intl:
- dependency: transitive
+ dependency: "direct main"
description:
name: intl
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
@@ -574,10 +574,10 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
- sha256: "3dedc66ca3c0bef9e6a93c0999aee102556a450afcc1b7bcfeace7a424927d92"
+ sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2"
url: "https://pub.dev"
source: hosted
- version: "6.1.3"
+ version: "6.1.4"
url_launcher_linux:
dependency: transitive
description:
@@ -630,10 +630,10 @@ packages:
dependency: transitive
description:
name: win32
- sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
+ sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
url: "https://pub.dev"
source: hosted
- version: "3.1.3"
+ version: "3.1.4"
xml:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 112486b..b43e4b4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -51,6 +51,7 @@ dependencies:
uri_to_file: ^0.2.0
uni_links: ^0.5.1
filesystem_picker: ^3.0.0-beta.1
+ intl: ^0.17.0
dev_dependencies: