From 32543e6d61b7a23b58bbf436ca191fe8dc3ba989 Mon Sep 17 00:00:00 2001 From: mabdc <747455334@qq.com> Date: Wed, 6 Sep 2023 20:53:03 +0800 Subject: [PATCH] =?UTF-8?q?###=202023.9.6=20-=20add=20=E6=9B=B4=E6=8D=A2?= =?UTF-8?q?=E9=9F=B3=E9=A2=91=E6=92=AD=E6=94=BE=E5=99=A8=E3=80=82=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=B3=BB=E7=BB=9F=E7=8A=B6=E6=80=81=E6=A0=8F=E6=A0=87?= =?UTF-8?q?=E7=AD=BE=EF=BC=8C=E5=93=8D=E5=BA=94=E7=B3=BB=E7=BB=9F=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E3=80=82=20-=20fix=20=E4=BF=AE=E5=A4=8D=E5=A4=87?= =?UTF-8?q?=E4=BB=BD=E6=96=87=E4=BB=B6=E7=BC=96=E7=A0=81=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20-=20add=20=E9=80=89=E5=8F=96=E5=A4=87=E4=BB=BD=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A2=9E=E6=B7=BB=E5=8F=AF=E4=BB=A5=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E6=96=87=E4=BB=B6=E7=AE=A1=E7=90=86=E5=99=A8?= =?UTF-8?q?=20-=20=E6=9A=82=E6=97=B6=E7=A7=BB=E9=99=A4=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E5=8E=86=E5=8F=B2=20-=20=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=92=8Cjs=E6=96=87=E6=9C=AC=E7=BC=96=E8=BE=91=E6=A1=86?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=92=A4=E9=94=80=E5=92=8C=E9=87=8D=E5=81=9A?= =?UTF-8?q?=EF=BC=88=E5=88=92=E6=8E=89=E3=80=82=E6=97=A7=E7=89=88flutter?= =?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81=EF=BC=89=20-=20=E7=9B=AE=E5=BD=95?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E5=8A=A0=E8=BD=BD=20-=20=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E6=97=B6=E5=A4=9A=E9=A1=B5=E7=9B=AE=E5=BD=95=E5=8F=AA=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E4=B8=80=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 9 ++ lib/api/api_from_rule.dart | 121 ++++++++++++++++++++++++++- lib/api/api_manager.dart | 6 +- lib/model/chapter_page_provider.dart | 52 +++++++++++- lib/model/debug_rule_provider.dart | 3 +- lib/page/chapter_page.dart | 66 ++++++++++++++- lib/page/search_page.dart | 4 +- lib/page/source/edit_rule_page.dart | 13 +++ 8 files changed, 263 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d105a394..8df4b945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +### 2023.9.6 +- add 更换音频播放器。增加系统状态栏标签,响应系统事件。 +- fix 修复备份文件编码问题 +- add 选取备份文件增添可以使用系统文件管理器 +- 暂时移除搜索界面历史 +- 规则和js文本编辑框添加撤销和重做(划掉。旧版flutter不支持) +- 目录分页加载 +- 调试时多页目录只加载一页 + ### 2023.4.22 - fix 书架分组自动保存 - fix 新发现瀑布流。标识符改成`@@DiscoverRule:`,其用来分隔js和json diff --git a/lib/api/api_from_rule.dart b/lib/api/api_from_rule.dart index 99f571df..8342bb6e 100644 --- a/lib/api/api_from_rule.dart +++ b/lib/api/api_from_rule.dart @@ -193,13 +193,129 @@ class APIFromRUle implements API { return result; } + String checkString(String s) => s != null && s.isNotEmpty ? s : null; + static String chapterNextUrl; + // page放进chapter里头 @override - Future> chapter(final String lastResult) async { + Future> chapter(final String lastResult, [int page]) async { if (rule.chapterUrl == "正文") { return [ChapterItem(url: lastResult, name: "正文")]; } API.chapterUrl = null; + if (page != null) { + // 这里拦截再退出 + final result = []; + final reversed = false; //rule.chapterList.startsWith("-"); //暂时关闭 + if (page == 1) { + chapterNextUrl = null; + } + try { + final url = + checkString(chapterNextUrl) ?? checkString(rule.chapterUrl) ?? lastResult; + var chapterUrl = url; + API.chapterUrl = chapterUrl; + var body = ''; + if (url != "null") { + final res = await AnalyzeUrl.urlRuleParser( + url, + rule, + result: lastResult, + page: page, + ); + if (res != null) { + if (res.contentLength == 0) { + return result; + } + chapterUrl = res.request.url.toString(); + API.chapterUrl = chapterUrl; + body = DecodeBody().decode(res.bodyBytes, res.headers["content-type"]); + } + } + if (page == 1) { + await JSEngine.setEnvironment(page, rule, "", chapterUrl, "", lastResult); + } else { + await JSEngine.evaluate( + "baseUrl = ${jsonEncode(chapterUrl)}; page = ${jsonEncode(page)};"); + } + final bodyAnalyzer = AnalyzerManager(body); + if (rule.chapterNextUrl != null && rule.chapterNextUrl.isNotEmpty) { + chapterNextUrl = await bodyAnalyzer.getString(rule.chapterNextUrl); + } + if (rule.enableMultiRoads) { + final roads = await bodyAnalyzer.getElements(rule.chapterRoads); + if (roads.isEmpty) { + return result; + } + for (final road in roads) { + final roadAnalyzer = AnalyzerManager(road); + result.add(ChapterItem( + name: "@线路" + await roadAnalyzer.getString(rule.chapterRoadName), + )); + final list = await roadAnalyzer + .getElements(reversed ? rule.chapterList.substring(1) : rule.chapterList); + if (list.isEmpty) { + break; + } + for (final item in (reversed ? list.reversed : list)) { + final analyzer = AnalyzerManager(item); + final lock = await analyzer.getString(rule.chapterLock); + // final unLock = await analyzer.getString(rule.chapterUnLock); + var name = (await analyzer.getString(rule.chapterName)) + .trim() + .replaceAll(APIConst.largeSpaceRegExp, Global.fullSpace); + // if (unLock != null && unLock.isNotEmpty && unLock != "undefined" && unLock != "false") { + // name = "🔓" + name; + // }else + if (lock != null && + lock.isNotEmpty && + lock != "undefined" && + lock != "false" && + lock != "0") { + name = "🔒" + name; + } + result.add(ChapterItem( + cover: await analyzer.getString(rule.chapterCover), + name: name, + time: await analyzer.getString(rule.chapterTime), + url: await analyzer.getString(rule.chapterResult), + )); + } + } + } else { + final list = await bodyAnalyzer + .getElements(reversed ? rule.chapterList.substring(1) : rule.chapterList); + if (list.isEmpty) { + return result; + } + for (final item in (reversed ? list.reversed : list)) { + final analyzer = AnalyzerManager(item); + final lock = await analyzer.getString(rule.chapterLock); + // final unLock = await analyzer.getString(rule.chapterUnLock); + var name = (await analyzer.getString(rule.chapterName)) + .trim() + .replaceAll(APIConst.largeSpaceRegExp, Global.fullSpace); + // if (unLock != null && unLock.isNotEmpty && unLock != "undefined" && unLock != "false") { + // name = "🔓" + name; + // }else + if (lock != null && + lock.isNotEmpty && + lock != "undefined" && + lock != "false" && + lock != "0") { + name = "🔒" + name; + } + result.add(ChapterItem( + cover: await analyzer.getString(rule.chapterCover), + name: name, + time: await analyzer.getString(rule.chapterTime), + url: await analyzer.getString(rule.chapterResult), + )); + } + } + } catch (e) {} + return result; + } final result = []; final reversed = rule.chapterList.startsWith("-"); final hasNextUrlRule = rule.chapterNextUrl != null && rule.chapterNextUrl.isNotEmpty; @@ -223,7 +339,8 @@ class APIFromRUle implements API { break; } try { - var chapterUrl = ''; + var chapterUrl = chapterUrlRule; + API.chapterUrl = chapterUrl; var body = ''; if (chapterUrlRule != 'null') { final res = await AnalyzeUrl.urlRuleParser( diff --git a/lib/api/api_manager.dart b/lib/api/api_manager.dart index 284a70ee..39359f9b 100644 --- a/lib/api/api_manager.dart +++ b/lib/api/api_manager.dart @@ -5,7 +5,7 @@ import '../global.dart'; import 'api.dart'; class APIManager { - static Future chooseAPI(String originTag) async { + static Future chooseAPI(String originTag) async { return APIFromRUle(await Global.ruleDao.findRuleById(originTag)); } @@ -28,10 +28,10 @@ class APIManager { return []; } - static Future> getChapter(String originTag, String url) async { + static Future> getChapter(String originTag, String url, [int page]) async { if (originTag != null) { final api = await chooseAPI(originTag); - if (api != null) return api.chapter(url); + if (api != null) return api.chapter(url, page); } return []; } diff --git a/lib/model/chapter_page_provider.dart b/lib/model/chapter_page_provider.dart index 81fdc123..2e42bee2 100644 --- a/lib/model/chapter_page_provider.dart +++ b/lib/model/chapter_page_provider.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:io'; import 'package:eso/api/api.dart'; @@ -11,6 +12,7 @@ import 'package:flutter/services.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import '../api/api_manager.dart'; +import '../database/chapter_item.dart'; import '../database/search_item.dart'; import '../database/search_item_manager.dart'; import '../global.dart'; @@ -97,9 +99,51 @@ class ChapterPageProvider with ChangeNotifier { notifyListeners(); } + int _page = -1; + int get page => _page; + String checkContent; + + Future loadChpaterWithPage(int page) async { + if (_page == 1) { + _page++; + notifyListeners(); + checkContent = buildCheck(searchItem.chapters); + } + await Duration(milliseconds: 500); // 随意休息一下 + print("加载目录$page"); + final durChapters = + await APIManager.getChapter(searchItem.originTag, searchItem.url, _page); + if (durChapters.isEmpty) { + _page = -page; // 结束 + _isLoading = false; + notifyListeners(); + return; + } + final _checkContent = buildCheck(durChapters); + if (checkContent == _checkContent) { + _page = -page; // 结束 + _isLoading = false; + notifyListeners(); + return; + } + searchItem.chapters.addAll(durChapters); + searchItem.chaptersCount = searchItem.chapters?.length ?? 0; + searchItem.chapter = searchItem.chapters?.last?.name; + _page++; + notifyListeners(); + loadChpaterWithPage(_page); + } + + String buildCheck(List chapters) { + return json.encode(chapters.first.toJson()) + + searchItem.chapters.length.toString() + + json.encode(chapters.last.toJson()); + } + void initChapters() async { + _page = 1; searchItem.chapters = - await APIManager.getChapter(searchItem.originTag, searchItem.url); + await APIManager.getChapter(searchItem.originTag, searchItem.url, page); searchItem.chapterUrl = API.chapterUrl; searchItem.durChapterIndex = 0; searchItem.durContentIndex = 1; @@ -107,10 +151,12 @@ class ChapterPageProvider with ChangeNotifier { searchItem.durChapter = ''; searchItem.chaptersCount = 0; searchItem.chapter = ''; + _page = 0; } else { searchItem.durChapter = searchItem.chapters?.first?.name ?? ''; searchItem.chaptersCount = searchItem.chapters?.length ?? 0; searchItem.chapter = searchItem.chapters?.last?.name; + loadChpaterWithPage(_page); } _isLoading = false; notifyListeners(); @@ -128,8 +174,10 @@ class ChapterPageProvider with ChangeNotifier { searchItem.chaptersCount = searchItem.chapters.length; if (searchItem.chaptersCount > 0) { searchItem.chapter = searchItem.chapters.last?.name; + _page = 1; + loadChpaterWithPage(_page); } else { - searchItem.chapter = ''; + _page = 0; } if (SearchItemManager.isFavorite(searchItem.originTag, searchItem.url)) { await searchItem.save(); diff --git a/lib/model/debug_rule_provider.dart b/lib/model/debug_rule_provider.dart index b5f833c7..907ba589 100644 --- a/lib/model/debug_rule_provider.dart +++ b/lib/model/debug_rule_provider.dart @@ -488,11 +488,12 @@ class DebugRuleProvider with ChangeNotifier { return; } _beginEvent("目录"); + _addContent("如果有分页,只尝试加载两页作为测试"); dynamic firstChapter; String next; String chapterUrlRule; final hasNextUrlRule = rule.chapterNextUrl != null && rule.chapterNextUrl.isNotEmpty; - for (var page = 1;; page++) { + for (var page = 1; page < 3; page++) { if (disposeFlag) return; chapterUrlRule = null; final url = rule.chapterUrl != null && rule.chapterUrl.isNotEmpty diff --git a/lib/page/chapter_page.dart b/lib/page/chapter_page.dart index 7fd75562..1580d9ca 100644 --- a/lib/page/chapter_page.dart +++ b/lib/page/chapter_page.dart @@ -6,6 +6,7 @@ import 'package:eso/menu/menu.dart'; import 'package:eso/menu/menu_chapter.dart'; import 'package:eso/eso_theme.dart'; import 'package:eso/page/photo_view_page.dart'; +import 'package:flutter/foundation.dart'; import 'package:text_composition/text_composition.dart'; import 'package:eso/ui/ui_image_item.dart'; import 'package:eso/utils.dart'; @@ -21,6 +22,47 @@ import '../model/chapter_page_provider.dart'; import 'content_page_manager.dart'; import 'langding_page.dart'; +class NextPageAnimation extends StatefulWidget { + final String text; + const NextPageAnimation({Key key, this.text = "加载下一页。。。"}) : super(key: key); + + @override + State createState() => _NextPageAnimationState(); +} + +class _NextPageAnimationState extends State { + int count = 0; + + @override + void initState() { + start(); + super.initState(); + } + + @override + void dispose() { + count = -1; + super.dispose(); + } + + void start() { + if (count == -1 || !mounted) return; + if (kDebugMode) { + print("播放动画 $count"); + } + Future.delayed(const Duration(milliseconds: 200), start); + setState(() { + count++; + }); + } + + @override + Widget build(BuildContext context) { + final text = widget.text; + return Text(text.substring(0, count % (text.length + 1))); + } +} + class ChapterPage extends StatefulWidget { final SearchItem searchItem; final bool fromHistory; @@ -89,13 +131,35 @@ class _ChapterPageState extends State { height: topHeight, ); }, - ) + ), + buildPage(context), ], )), ), ); } + Widget buildPage(BuildContext context) { + final page = Provider.of(context, listen: true).page; + print(page); + if (page > 0) + return Positioned( + right: 20, + bottom: 10, + child: Row( + children: [ + Text("${Provider.of(context).page}"), + NextPageAnimation(text: "页加载中") + ], + ), + ); + return Positioned( + right: 20, + bottom: 10, + child: Card(child: Text("${-Provider.of(context).page}页")), + ); + } + //头部 Widget _buildAlphaAppbar(BuildContext context) { final provider = Provider.of(context, listen: false); diff --git a/lib/page/search_page.dart b/lib/page/search_page.dart index 42d58798..d00252ab 100644 --- a/lib/page/search_page.dart +++ b/lib/page/search_page.dart @@ -543,7 +543,7 @@ class SearchProvider with ChangeNotifier { List _history; List get history => _history; bool _showHistory; - bool get showHistory => _showHistory; + bool get showHistory => false; //_showHistory; SearchProvider({ int threadCount, SearchOption searchOption, @@ -584,7 +584,7 @@ class SearchProvider with ChangeNotifier { _showHistory = true; notifyListeners(); } else { - Future.delayed(Duration(milliseconds: 100), closeHistory); + Future.delayed(Duration(milliseconds: 100), closeHistory); } } diff --git a/lib/page/source/edit_rule_page.dart b/lib/page/source/edit_rule_page.dart index faa2e2c6..2cd82724 100644 --- a/lib/page/source/edit_rule_page.dart +++ b/lib/page/source/edit_rule_page.dart @@ -226,6 +226,18 @@ class _EditRulePageState extends State with WidgetsBindingObserver titleSpacing: 0, title: Text(widget.rule == null ? '新建规则' : '编辑规则'), actions: [ + // IconButton( + // icon: Icon(Icons.undo_rounded), + // tooltip: "撤销", + // onPressed: + // editContentHistory.value.canUndo ? editContentHistory.undo : null, + // ), + // IconButton( + // icon: Icon(Icons.redo_rounded), + // tooltip: "重做", + // onPressed: + // editContentHistory.value.canRedo ? editContentHistory.redo : null, + // ), IconButton( icon: Icon(FIcons.share_2), tooltip: "分享", @@ -469,6 +481,7 @@ class _EditRulePageState extends State with WidgetsBindingObserver TextEditingController currentController; void Function(String text) currentOnChanged; + // UndoHistoryController currentController; Widget _buildEditText( String text,