From 088453f1ad9a07add2486522bb9b10d9be65fa60 Mon Sep 17 00:00:00 2001 From: niuhuan Date: Thu, 21 Oct 2021 12:08:51 +0800 Subject: [PATCH] add comment --- .../kotlin/niuhuan/pikapi/MainActivity.kt | 62 ------- lib/basic/Channels.dart | 4 + lib/basic/Common.dart | 1 + lib/basic/Cross.dart | 2 + lib/basic/Entities.dart | 29 ++++ lib/basic/Method.dart | 159 ++++++++++-------- lib/basic/config/AutoFullScreen.dart | 17 +- lib/basic/config/Quality.dart | 75 ++++++--- lib/basic/config/ShadowCategories.dart | 43 ++++- lib/basic/config/Themes.dart | 14 +- lib/screens/ComicReaderScreen.dart | 4 +- lib/screens/DownloadReaderScreen.dart | 2 +- lib/screens/SettingsScreen.dart | 18 +- 13 files changed, 239 insertions(+), 191 deletions(-) diff --git a/android/app/src/main/kotlin/niuhuan/pikapi/MainActivity.kt b/android/app/src/main/kotlin/niuhuan/pikapi/MainActivity.kt index ab4a00a..fb5d1e5 100644 --- a/android/app/src/main/kotlin/niuhuan/pikapi/MainActivity.kt +++ b/android/app/src/main/kotlin/niuhuan/pikapi/MainActivity.kt @@ -92,9 +92,6 @@ class MainActivity : FlutterActivity() { setMode(call.argument("mode")!!) } "androidGetVersion" -> Build.VERSION.SDK_INT -// "exportComicDownloadAndroidQ" -> { -// exportComicDownloadAndroidQ(call.argument("comicId")!!) -// } // 现在的文件储存路径, 默认路径返回空字符串 "" "dataLocal" -> androidDataLocal() // 迁移到那个地方, 如果是空字符串则迁移会默认位置 @@ -341,63 +338,4 @@ class MainActivity : FlutterActivity() { return super.onKeyDown(keyCode, event) } -// 安卓11以上使用了 MANAGE_EXTERNAL_STORAGE 权限来管理整个外置存储 (危险权限) -// private val resourceQueue: LinkedBlockingQueue = LinkedBlockingQueue() -// 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().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)) -// } -// } -// } - } diff --git a/lib/basic/Channels.dart b/lib/basic/Channels.dart index 229e017..da81dc6 100644 --- a/lib/basic/Channels.dart +++ b/lib/basic/Channels.dart @@ -3,6 +3,10 @@ import 'dart:convert'; import 'package:flutter/services.dart'; +// EventChannel +// 由于Flutter的EventChannel只能订阅一次, 且为了和golang的的通信, 这里实现了多次订阅的分发和平铺 +// 根据eventName订阅和取消订阅 + var _eventChannel = EventChannel("flatEvent"); StreamSubscription? _eventChannelListen; diff --git a/lib/basic/Common.dart b/lib/basic/Common.dart index 3bfdf78..e64a461 100644 --- a/lib/basic/Common.dart +++ b/lib/basic/Common.dart @@ -3,6 +3,7 @@ import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'config/TimeOffsetHour.dart'; +/// 默认的图片尺寸 double coverWidth = 210; double coverHeight = 315; diff --git a/lib/basic/Cross.dart b/lib/basic/Cross.dart index 2b07782..335e5ac 100644 --- a/lib/basic/Cross.dart +++ b/lib/basic/Cross.dart @@ -58,6 +58,7 @@ Future saveImage(String path, BuildContext context) async { } } +/// 保存图片且保持静默, 用于批量导出到相册 Future saveImageQuiet(String path, BuildContext context) async { if (Platform.isIOS) { return method.iosSaveFileToImage(path); @@ -98,6 +99,7 @@ Future chooseFolder(BuildContext context) async { ); } +/// 复制对话框 void confirmCopy(BuildContext context, String content) async { if (await confirmDialog(context, "复制", content)) { copyToClipBoard(context, content); diff --git a/lib/basic/Entities.dart b/lib/basic/Entities.dart index 375d6a3..1011e15 100644 --- a/lib/basic/Entities.dart +++ b/lib/basic/Entities.dart @@ -1,3 +1,4 @@ +/// 图片 class PicaImage { late String originalName; late String path; @@ -10,6 +11,7 @@ class PicaImage { } } +/// 用户基本信息 class BasicUser { late String id; late String gender; @@ -34,6 +36,7 @@ class BasicUser { } } +/// 用户自己的信息 class UserProfile extends BasicUser { late String birthday; late String email; @@ -48,6 +51,7 @@ class UserProfile extends BasicUser { } } +/// 分页 class Page { late int total; late int limit; @@ -62,6 +66,7 @@ class Page { } } +/// 分类 class Category { late String id; late String title; @@ -82,6 +87,7 @@ class Category { } } +/// 漫画分页 class ComicsPage extends Page { late List docs; @@ -93,6 +99,7 @@ class ComicsPage extends Page { } } +/// 漫画基本信息 class ComicSimple { late String id; late String title; @@ -117,6 +124,7 @@ class ComicSimple { } } +/// 漫画详情 class ComicInfo extends ComicSimple { late String description; late String chineseTeam; @@ -145,6 +153,7 @@ class ComicInfo extends ComicSimple { } } +/// 漫画创建人信息 class Creator extends BasicUser { late String slogan; late String role; @@ -157,6 +166,7 @@ class Creator extends BasicUser { } } +/// 漫画章节 class Ep { late String id; late String title; @@ -171,6 +181,7 @@ class Ep { } } +/// 漫画章节分页 class EpPage extends Page { late List docs; @@ -182,6 +193,7 @@ class EpPage extends Page { } } +/// 漫画图片分页 class PicturePage extends Page { late List docs; @@ -193,6 +205,7 @@ class PicturePage extends Page { } } +/// 漫画图片信息 class Picture { late String id; late PicaImage media; @@ -203,6 +216,7 @@ class Picture { } } +/// 显示图片数据 class RemoteImageData { late int fileSize; late String format; @@ -227,6 +241,7 @@ class RemoteImageData { } } +/// 漫画评论分页 class CommentPage extends Page { late List docs; @@ -238,6 +253,7 @@ class CommentPage extends Page { } } +/// 漫画评论详情 class Comment { late String id; late String content; @@ -264,6 +280,7 @@ class Comment { } } +/// 评论的用户信息 class CommentUser extends BasicUser { late String role; @@ -272,6 +289,7 @@ class CommentUser extends BasicUser { } } +/// 已下载图片的信息 class DownloadPicture { late int rankInEp; late String fileServer; @@ -294,6 +312,7 @@ class DownloadPicture { } } +/// 浏览历史记录 class ViewLog { late String id; late String title; @@ -334,6 +353,7 @@ class ViewLog { } } +/// 已下载漫画的信息 class DownloadComic { late String id; late String createdAt; @@ -417,6 +437,7 @@ class DownloadComic { } } +/// 已下载的章节信息 class DownloadEp { late String comicId; late String id; @@ -447,6 +468,7 @@ class DownloadEp { } } +/// 游戏的分页 class GamePage extends Page { late List docs; @@ -458,6 +480,7 @@ class GamePage extends Page { } } +/// 游戏的简要信息 class GameSimple { late String id; late String title; @@ -484,6 +507,7 @@ class GameSimple { } } +/// 游戏详情 class GameInfo extends GameSimple { late String description; late String updateContent; @@ -519,6 +543,7 @@ class GameInfo extends GameSimple { } } +/// 我的评论页面分页 class MyCommentsPage extends Page { late List docs; @@ -528,6 +553,7 @@ class MyCommentsPage extends Page { } } +/// 我的评论 class MyComment { late String id; late String content; @@ -550,6 +576,7 @@ class MyComment { } } +/// 我的评论漫画简要信息 class MyCommentComic { late String id; late String title; @@ -560,6 +587,7 @@ class MyCommentComic { } } +/// 子评论分页 class CommentChildrenPage extends Page { late List docs; @@ -573,6 +601,7 @@ class CommentChildrenPage extends Page { } } +/// 子评论 class CommentChild extends Comment { late String parent; diff --git a/lib/basic/Method.dart b/lib/basic/Method.dart index 93ed314..efca422 100644 --- a/lib/basic/Method.dart +++ b/lib/basic/Method.dart @@ -4,13 +4,18 @@ import 'package:flutter/services.dart'; import 'package:pikapi/basic/Entities.dart'; import 'package:pikapi/basic/config/Quality.dart'; +/// 使用MethodChannel与平台通信 + final method = Method._(); class Method { + /// 禁止其他页面构造此类 Method._(); + /// channel MethodChannel _channel = MethodChannel("method"); + /// 平铺调用, 为了直接与golang进行通信 Future _flatInvoke(String method, dynamic params) { return _channel.invokeMethod("flatInvoke", { "method": method, @@ -18,20 +23,7 @@ class Method { }); } - Future loadTheme() async { - return await _flatInvoke("loadProperty", { - "name": "theme", - "defaultValue": "pink", - }); - } - - Future saveTheme(String code) async { - return await _flatInvoke("saveProperty", { - "name": "theme", - "value": code, - }); - } - + /// 读取配置文件 Future loadProperty(String propertyName, String defaultValue) async { return await _flatInvoke("loadProperty", { "name": propertyName, @@ -39,6 +31,7 @@ class Method { }); } + /// 保存配置文件 Future saveProperty(String propertyName, String value) { return _flatInvoke("saveProperty", { "name": propertyName, @@ -46,61 +39,59 @@ class Method { }); } - Future loadQuality() async { - return await _flatInvoke("loadProperty", { - "name": "quality", - "defaultValue": ImageQualityOriginal, - }); - } - - Future saveQuality(String code) async { - return await _flatInvoke("saveProperty", { - "name": "quality", - "value": code, - }); - } - + /// 获取当前的分流 Future getSwitchAddress() async { return await _flatInvoke("getSwitchAddress", ""); } + /// 更换分流 Future setSwitchAddress(String switchAddress) async { return await _flatInvoke("setSwitchAddress", switchAddress); } + /// 获取代理 Future getProxy() async { return await _flatInvoke("getProxy", ""); } + /// 更换当前的代理 Future setProxy(String proxy) async { return await _flatInvoke("setProxy", proxy); } + /// 获取用户名 Future getUsername() async { return await _flatInvoke("getUsername", ""); } + /// 设置用户名 Future setUsername(String username) async { return await _flatInvoke("setUsername", username); } + /// 获取密码 Future getPassword() async { return await _flatInvoke("getPassword", ""); } + /// 设置密码 Future setPassword(String password) async { return await _flatInvoke("setPassword", password); } + /// 预登录, 程序启用时会调用 + /// 如果又账号密码或token, 且登录成功, 将返回true Future preLogin() async { String rsp = await _flatInvoke("preLogin", ""); return rsp == "true"; } + /// 登录 Future login() async { return _flatInvoke("login", ""); } + /// 注册 Future register( String email, String name, @@ -128,19 +119,24 @@ class Method { }); } + /// 退出登录 Future clearToken() { return _flatInvoke("clearToken", ""); } + /// 获取用户自身基础信息 Future userProfile() async { String rsp = await _flatInvoke("userProfile", ""); return UserProfile.fromJson(json.decode(rsp)); } + /// 打卡 Future punchIn() { return _flatInvoke("punchIn", ""); } + /// 使用服务器地址以及路径获取图片用户显示 + /// 如果本地有缓存会返回路径, 如果本地没有缓存会下载再返回路径, 没有下载成功则会抛出异常 Future remoteImageData( String fileServer, String path) async { var data = await _flatInvoke("remoteImageData", { @@ -150,6 +146,7 @@ class Method { return RemoteImageData.fromJson(json.decode(data)); } + /// 功能同上, 用于预加载 Future remoteImagePreload(String fileServer, String path) async { return _flatInvoke("remoteImagePreload", { "fileServer": fileServer, @@ -157,16 +154,26 @@ class Method { }); } + /// 获取已经下载好图片的保存位置 Future downloadImagePath(String path) async { return await _flatInvoke("downloadImagePath", path); } + /// 获取分类 Future> categories() async { String rsp = await _flatInvoke("categories", ""); List list = json.decode(rsp); return list.map((e) => Category.fromJson(e)).toList(); } + /// 列出漫画 + /// [sort] 排序方式 + /// [page] 页数 + /// [category] 分类 + /// [tag] 标签 + /// [creatorId] 创建人ID + /// [chineseTeam] 汉化组名称 + /// * 几种条件使用且的关系 Future comics( String sort, int page, { @@ -186,10 +193,12 @@ class Method { return ComicsPage.fromJson(json.decode(rsp)); } + /// 搜索漫画 Future searchComics(String keyword, String sort, int page) { return searchComicsInCategories(keyword, sort, page, []); } + /// 搜索漫画, 在多个分类中 Future searchComicsInCategories( String keyword, String sort, int page, List categories) async { String rsp = await _flatInvoke("searchComics", { @@ -201,6 +210,7 @@ class Method { return ComicsPage.fromJson(json.decode(rsp)); } + /// 随机漫画 Future> randomComics() async { String data = await _flatInvoke("randomComics", ""); return List.of(jsonDecode(data)) @@ -209,6 +219,8 @@ class Method { .toList(); } + /// 漫画榜单 + /// [type] 榜单类型 H24 D7 D30 Future> leaderboard(String type) async { String data = await _flatInvoke("leaderboard", type); return List.of(jsonDecode(data)) @@ -217,11 +229,13 @@ class Method { .toList(); } + /// 获取漫画详情 Future comicInfo(String comicId) async { String rsp = await _flatInvoke("comicInfo", comicId); return ComicInfo.fromJson(json.decode(rsp)); } + /// 分页获取漫画的章节 Future comicEpPage(String comicId, int page) async { String rsp = await _flatInvoke("comicEpPage", { "comicId": comicId, @@ -230,6 +244,7 @@ class Method { return EpPage.fromJson(json.decode(rsp)); } + /// 分页获取一个章节的图片, 并且需要图片的质量参数 Future comicPicturePageWithQuality( String comicId, int epOrder, int page, String quality) async { String data = await _flatInvoke("comicPicturePageWithQuality", { @@ -241,14 +256,17 @@ class Method { return PicturePage.fromJson(json.decode(data)); } + /// 对漫画进行点赞/取消点赞操作 Future switchLike(String comicId) async { return await _flatInvoke("switchLike", comicId); } + /// 对漫画进行收藏/取消收藏操作 Future switchFavourite(String comicId) async { return await _flatInvoke("switchFavourite", comicId); } + /// 收藏漫画列表 Future favouriteComics(String sort, int page) async { var rsp = await _flatInvoke("favouriteComics", { "sort": sort, @@ -257,12 +275,14 @@ class Method { return ComicsPage.fromJson(json.decode(rsp)); } + /// 看了此漫画的人还看了...(此接口似乎失效了) Future> recommendation(String comicId) async { String rsp = await _flatInvoke("recommendation", comicId); List list = json.decode(rsp); return list.map((e) => ComicSimple.fromJson(e)).toList(); } + /// 对漫画发送评论 Future postComment(String comicId, String content) { return _flatInvoke("postComment", { "comicId": comicId, @@ -270,6 +290,7 @@ class Method { }); } + /// 发送子评论 Future postChildComment(String commentId, String content) { return _flatInvoke("postChildComment", { "commentId": commentId, @@ -277,6 +298,7 @@ class Method { }); } + /// 漫画的评论列表 Future comments(String comicId, int page) async { var rsp = await _flatInvoke("comments", { "comicId": comicId, @@ -285,6 +307,7 @@ class Method { return CommentPage.fromJson(json.decode(rsp)); } + /// 拉取子评论 Future commentChildren( String comicId, String commentId, @@ -298,13 +321,13 @@ class Method { return CommentChildrenPage.fromJson(json.decode(rsp)); } + /// 我的评论列表 Future myComments(int page) async { String response = await _flatInvoke("myComments", "$page"); - print("RESPONSE"); - print(response); return MyCommentsPage.fromJson(jsonDecode(response)); } + /// 浏览记录 Future> viewLogPage(int offset, int limit) async { var data = await _flatInvoke("viewLogPage", { "offset": offset, @@ -314,32 +337,39 @@ class Method { return list.map((e) => ViewLog.fromJson(e)).toList(); } + /// 清除所有的浏览记录 Future clearAllViewLog() { return _flatInvoke("clearAllViewLog", ""); } + /// 删除一个漫画的浏览记录 Future deleteViewLog(String id) { return _flatInvoke("deleteViewLog", id); } + /// 游戏列表 Future games(int page) async { var data = await _flatInvoke("games", "$page"); return GamePage.fromJson(json.decode(data)); } + /// 游戏详情 Future game(String gameId) async { var data = await _flatInvoke("game", gameId); return GameInfo.fromJson(json.decode(data)); } + /// 清理缓存 Future clean() { return _flatInvoke("clean", ""); } + /// 清理[expireSec]秒以前的缓存 Future autoClean(String expireSec) { return _flatInvoke("autoClean", expireSec); } + /// 保存当前浏览器的进度 Future storeViewEp( String comicId, int epOrder, String epTitle, int pictureRank) { return _flatInvoke("storeViewEp", { @@ -350,6 +380,7 @@ class Method { }); } + /// 加载浏览进度 Future loadView(String comicId) async { String data = await _flatInvoke("loadView", comicId); if (data == "") { @@ -358,15 +389,18 @@ class Method { return ViewLog.fromJson(jsonDecode(data)); } + /// 下载是否在后台运行 Future downloadRunning() async { String rsp = await _flatInvoke("downloadRunning", ""); return rsp == "true"; } + /// 暂停/继续 下载 Future setDownloadRunning(bool status) async { return _flatInvoke("setDownloadRunning", "$status"); } + /// 下载漫画 Future createDownload( Map comic, List> epList) async { return _flatInvoke("createDownload", { @@ -375,6 +409,7 @@ class Method { }); } + /// 追加下载的章节 Future addDownload( Map comic, List> epList) async { await _flatInvoke("addDownload", { @@ -383,6 +418,7 @@ class Method { }); } + /// 下载详情 Future loadDownloadComic(String comicId) async { var data = await _flatInvoke("loadDownloadComic", comicId); // 未找到 且 未异常 @@ -392,6 +428,7 @@ class Method { return DownloadComic.fromJson(json.decode(data)); } + /// 所有下载 Future> allDownloads() async { var data = await _flatInvoke("allDownloads", ""); data = jsonDecode(data); @@ -402,26 +439,31 @@ class Method { return list.map((e) => DownloadComic.fromJson(e)).toList(); } + /// 删除一个下载 Future deleteDownloadComic(String comicId) async { return _flatInvoke("deleteDownloadComic", comicId); } + /// 所有下载的EP Future> downloadEpList(String comicId) async { var data = await _flatInvoke("downloadEpList", comicId); List list = json.decode(data); return list.map((e) => DownloadEp.fromJson(e)).toList(); } + /// 下载漫画这个EP下的图片 Future> downloadPicturesByEpId(String epId) async { var data = await _flatInvoke("downloadPicturesByEpId", epId); List list = json.decode(data); return list.map((e) => DownloadPicture.fromJson(e)).toList(); } + /// 重置所有下载失败的漫画 Future resetFailed() async { return _flatInvoke("resetAllDownloads", ""); } + /// 导出下载的漫画到zip Future exportComicDownload(String comicId, String dir) { return _flatInvoke("exportComicDownload", { "comicId": comicId, @@ -429,12 +471,7 @@ class Method { }); } - Future exportComicDownloadAndroidQ(String comicId) { - return _channel.invokeMethod("exportComicDownloadAndroidQ", { - "comicId": comicId, - }); - } - + /// 导出下载的图片到HTML+JPG Future exportComicDownloadToJPG(String comicId, String dir) { return _flatInvoke("exportComicDownloadToJPG", { "comicId": comicId, @@ -442,26 +479,32 @@ class Method { }); } + /// 使用网络将下载传输到其他设备 Future exportComicUsingSocket(String comicId) async { return int.parse(await _flatInvoke("exportComicUsingSocket", comicId)); } + /// 传输窗口关闭时调用, 令socket关闭(如果传输没有结束) Future exportComicUsingSocketExit() { return _flatInvoke("exportComicUsingSocketExit", ""); } + /// 从zip导入漫画 Future importComicDownload(String zipPath) { return _flatInvoke("importComicDownload", zipPath); } + /// 从网络接收漫画 Future importComicDownloadUsingSocket(String addr) { return _flatInvoke("importComicDownloadUsingSocket", addr); } + /// 获取本机的所有ip地址 Future clientIpSet() async { return await _flatInvoke("clientIpSet", ""); } + /// 获取一个游戏的下载地址 Future> downloadGame(String url) async { if (url.startsWith("https://game.eroge.xyz/hhh.php")) { var data = await _flatInvoke("downloadGame", url); @@ -470,18 +513,21 @@ class Method { return [url]; } + /// 保存图片(ios) Future iosSaveFileToImage(String path) async { return _channel.invokeMethod("iosSaveFileToImage", { "path": path, }); } + /// 保存图片(android) Future androidSaveFileToImage(String path) async { return _channel.invokeMethod("androidSaveFileToImage", { "path": path, }); } + /// 保存图片(PC) Future convertImageToJPEG100(String path, String dir) async { return _flatInvoke("convertImageToJPEG100", { "path": path, @@ -489,59 +535,30 @@ class Method { }); } - Future getAutoFullScreen() async { - var value = await _flatInvoke("loadProperty", { - "name": "autoFullScreen", - "defaultValue": "false", - }); - return value == "true"; - } - - Future setAutoFullScreen(bool value) async { - return await _flatInvoke("saveProperty", { - "name": "autoFullScreen", - "value": "$value", - }); - } - - Future> getShadowCategories() async { - var value = await _flatInvoke("loadProperty", { - "name": "shadowCategories", - "defaultValue": jsonEncode([]), - }); - return List.of(jsonDecode(value)).map((e) => "$e").toList(); - } - - Future setShadowCategories(List value) { - return _flatInvoke("saveProperty", { - "name": "shadowCategories", - "value": jsonEncode(value), - }); - } - + /// 获取安卓的屏幕刷新率 Future> loadAndroidModes() async { return List.of(await _channel.invokeMethod("androidGetModes")) .map((e) => "$e") .toList(); } + /// 设置安卓的屏幕刷新率 Future setAndroidMode(String androidDisplayMode) { return _channel .invokeMethod("androidSetMode", {"mode": androidDisplayMode}); } - Future androidGetUiMode() { - return _channel.invokeMethod("androidGetUiMode", {}); - } - + /// 获取安卓的版本 Future androidGetVersion() async { return await _channel.invokeMethod("androidGetVersion", {}); } + /// 数据文件保存位置 Future dataLocal() async { return await _channel.invokeMethod("dataLocal", {}); } + /// 获取安卓支持的文件保存路径 Future> androidGetExtendDirs() async { String? tmp = await _channel.invokeMethod("androidGetExtendDirs", {}); if (tmp != null && tmp.isNotEmpty) { @@ -550,7 +567,9 @@ class Method { return []; } + /// 安卓文件迁移 Future migrate(String path) async { return _channel.invokeMethod("migrate", {"path": path}); } + } diff --git a/lib/basic/config/AutoFullScreen.dart b/lib/basic/config/AutoFullScreen.dart index d166e22..c31c08a 100644 --- a/lib/basic/config/AutoFullScreen.dart +++ b/lib/basic/config/AutoFullScreen.dart @@ -5,14 +5,21 @@ import 'package:flutter/material.dart'; import '../Common.dart'; import '../Method.dart'; -late bool gAutoFullScreen; +late bool _autoFullScreen; + +bool currentAutoFullScreen() { + return _autoFullScreen; +} + +const _propertyName = "autoFullScreen"; Future initAutoFullScreen() async { - gAutoFullScreen = await method.getAutoFullScreen(); + _autoFullScreen = + (await method.loadProperty(_propertyName, "false")) == "true"; } String autoFullScreenName() { - return gAutoFullScreen ? "是" : "否"; + return _autoFullScreen ? "是" : "否"; } Future chooseAutoFullScreen(BuildContext context) async { @@ -20,7 +27,7 @@ Future chooseAutoFullScreen(BuildContext context) async { await chooseListDialog(context, "进入阅读器自动全屏", ["是", "否"]); if (result != null) { var target = result == "是"; - await method.setAutoFullScreen(target); - gAutoFullScreen = target; + await method.saveProperty(_propertyName, "$target"); + _autoFullScreen = target; } } diff --git a/lib/basic/config/Quality.dart b/lib/basic/config/Quality.dart index 7ff7a4f..6c49546 100644 --- a/lib/basic/config/Quality.dart +++ b/lib/basic/config/Quality.dart @@ -1,32 +1,47 @@ /// 图片质量 import 'package:flutter/material.dart'; - import '../Method.dart'; -late String currentQualityCode; - -Future initQuality() async { - currentQualityCode = await method.loadQuality(); -} - -const ImageQualityOriginal = "original"; -const ImageQualityLow = "low"; -const ImageQualityMedium = "medium"; +const _ImageQualityOriginal = "original"; +const _ImageQualityLow = "low"; +const _ImageQualityMedium = "medium"; const ImageQualityHigh = "high"; -const LabelOriginal = "原图"; -const LabelLow = "低"; -const LabelMedium = "中"; -const LabelHigh = "高"; +const _LabelOriginal = "原图"; +const _LabelLow = "低"; +const _LabelMedium = "中"; +const _LabelHigh = "高"; var _qualities = { - LabelOriginal: ImageQualityOriginal, - LabelLow: ImageQualityLow, - LabelMedium: ImageQualityMedium, - LabelHigh: ImageQualityHigh, + _LabelOriginal: _ImageQualityOriginal, + _LabelLow: _ImageQualityLow, + _LabelMedium: _ImageQualityMedium, + _LabelHigh: ImageQualityHigh, }; +late String _currentQualityCode; + +String currentQualityCode() { + return _currentQualityCode; +} + +String _currentQualityName() { + for (var e in _qualities.entries) { + if (e.value == _currentQualityCode) { + return e.key; + } + } + return ''; +} + +const _propertyName = "quality"; +const _defaultValue = _ImageQualityOriginal; + +Future initQuality() async { + _currentQualityCode = await method.loadProperty(_propertyName, _defaultValue); +} + Future chooseQuality(BuildContext context) async { String? code = await showDialog( context: context, @@ -47,16 +62,22 @@ Future chooseQuality(BuildContext context) async { }, ); if (code != null) { - method.saveQuality(code); - currentQualityCode = code; + method.saveProperty(_propertyName, code); + _currentQualityCode = code; } } -String currentQualityName() { - for (var e in _qualities.entries) { - if (e.value == currentQualityCode) { - return e.key; - } - } - return ''; +Widget qualitySetting() { + return StatefulBuilder( + builder: (BuildContext context, void Function(void Function()) setState) { + return ListTile( + title: Text("浏览时的图片质量"), + subtitle: Text(_currentQualityName()), + onTap: () async { + await chooseQuality(context); + setState(() {}); + }, + ); + }, + ); } diff --git a/lib/basic/config/ShadowCategories.dart b/lib/basic/config/ShadowCategories.dart index 0118e01..4470cbe 100644 --- a/lib/basic/config/ShadowCategories.dart +++ b/lib/basic/config/ShadowCategories.dart @@ -1,5 +1,7 @@ /// 屏蔽的分类 +import 'dart:convert'; + import 'package:event/event.dart'; import 'package:flutter/material.dart'; import 'package:multi_select_flutter/dialog/mult_select_dialog.dart'; @@ -9,14 +11,28 @@ import '../Method.dart'; import '../store/Categories.dart'; late List shadowCategories; - var shadowCategoriesEvent = Event(); -Future initShadowCategories() async { - shadowCategories = await method.getShadowCategories(); +// mapper + +const _propertyName = "shadowCategories"; + +/// 获取封印的类型 +Future> _loadShadowCategories() async { + var value = await method.loadProperty(_propertyName, jsonEncode([])); + return List.of(jsonDecode(value)).map((e) => "$e").toList(); } -Future chooseShadowCategories(BuildContext context) async { +/// 保存封印的类型 +Future _saveShadowCategories(List value) { + return method.saveProperty(_propertyName, jsonEncode(value)); +} + +Future initShadowCategories() async { + shadowCategories = await _loadShadowCategories(); +} + +Future _chooseShadowCategories(BuildContext context) async { await showDialog( context: context, builder: (ctx) { @@ -35,7 +51,7 @@ Future chooseShadowCategories(BuildContext context) async { initialValue: initialValue, onConfirm: (List? value) async { if (value != null) { - await method.setShadowCategories(value); + await _saveShadowCategories(value); shadowCategories = value; shadowCategoriesEvent.broadcast(); } @@ -48,8 +64,23 @@ Future chooseShadowCategories(BuildContext context) async { Widget shadowCategoriesActionButton(BuildContext context) { return IconButton( onPressed: () { - chooseShadowCategories(context); + _chooseShadowCategories(context); }, icon: Icon(Icons.hide_source), ); } + +Widget shadowCategoriesSetting() { + return StatefulBuilder( + builder: (BuildContext context, void Function(void Function()) setState) { + return ListTile( + title: Text("封印"), + subtitle: Text(jsonEncode(shadowCategories)), + onTap: () async { + await _chooseShadowCategories(context); + setState(() {}); + }, + ); + }, + ); +} diff --git a/lib/basic/config/Themes.dart b/lib/basic/config/Themes.dart index 063723d..1c9c018 100644 --- a/lib/basic/config/Themes.dart +++ b/lib/basic/config/Themes.dart @@ -7,6 +7,9 @@ import 'package:pikapi/basic/Common.dart'; import '../Method.dart'; import 'Platform.dart'; + +// 字体相关 + const _fontFamilyProperty = "fontFamily"; String? _fontFamily; @@ -50,6 +53,8 @@ Widget fontSetting() { ); } +// 主题相关 + // 主题包 abstract class _ThemePackage { String code(); @@ -168,6 +173,9 @@ final _themePackages = <_ThemePackage>[ // 主题更换事件 var themeEvent = Event(); +const _themePropertyName = "theme"; +const _defaultThemeCode = "pink"; + String? _themeCode; ThemeData? _themeData; ThemeData? _currentDarkTheme; @@ -217,7 +225,9 @@ const _nightModePropertyName = "androidNightMode"; Future initTheme() async { _androidNightMode = await method.loadProperty(_nightModePropertyName, "true") == "true"; - _changeThemeByCode(await method.loadTheme()); + _changeThemeByCode( + await method.loadProperty(_themePropertyName, _defaultThemeCode), + ); } // 选择主题的对话框 @@ -292,7 +302,7 @@ Future chooseTheme(BuildContext buildContext) async { }, ); if (theme != null) { - method.saveTheme(theme); + method.saveProperty(_themePropertyName, theme); _changeThemeByCode(theme); } } diff --git a/lib/screens/ComicReaderScreen.dart b/lib/screens/ComicReaderScreen.dart index d111db2..ded8116 100644 --- a/lib/screens/ComicReaderScreen.dart +++ b/lib/screens/ComicReaderScreen.dart @@ -30,7 +30,7 @@ class ComicReaderScreen extends StatefulWidget { this.initPictureRank, bool? autoFullScreen, }) : super(key: key) { - this.autoFullScreen = autoFullScreen ?? gAutoFullScreen; + this.autoFullScreen = autoFullScreen ?? currentAutoFullScreen(); } @override @@ -56,7 +56,7 @@ class _ComicReaderScreenState extends State { widget.comicInfo.id, widget.currentEpOrder, ++_needLoadPage, - currentQualityCode, + currentQualityCode(), ); list.addAll(page.docs.map((element) => element.media)); } while (page.pages > page.page); diff --git a/lib/screens/DownloadReaderScreen.dart b/lib/screens/DownloadReaderScreen.dart index de54d7e..844ff38 100644 --- a/lib/screens/DownloadReaderScreen.dart +++ b/lib/screens/DownloadReaderScreen.dart @@ -29,7 +29,7 @@ class DownloadReaderScreen extends StatefulWidget { this.initPictureRank, bool? autoFullScreen, }) : super(key: key) { - this.autoFullScreen = autoFullScreen ?? gAutoFullScreen; + this.autoFullScreen = autoFullScreen ?? currentAutoFullScreen(); } @override diff --git a/lib/screens/SettingsScreen.dart b/lib/screens/SettingsScreen.dart index 98e3d02..3bf3269 100644 --- a/lib/screens/SettingsScreen.dart +++ b/lib/screens/SettingsScreen.dart @@ -38,14 +38,7 @@ class _SettingsScreenState extends State { Divider(), NetworkSetting(), Divider(), - ListTile( - title: Text("浏览时的图片质量"), - subtitle: Text(currentQualityName()), - onTap: () async { - await chooseQuality(context); - setState(() {}); - }, - ), + qualitySetting(), ListTile( title: Text("阅读器模式"), subtitle: Text(currentReaderTypeName()), @@ -81,14 +74,7 @@ class _SettingsScreenState extends State { volumeControllerSetting(), keyboardControllerSetting(), Divider(), - ListTile( - title: Text("封印"), - subtitle: Text(jsonEncode(shadowCategories)), - onTap: () async { - await chooseShadowCategories(context); - setState(() {}); - }, - ), + shadowCategoriesSetting(), ListTile( title: Text("列表页加载方式"), subtitle: Text(currentPagerActionName()),