From c096f5a2d813d4fdf85fdc6ef8d38b0bdcdd5585 Mon Sep 17 00:00:00 2001 From: nyne Date: Sat, 5 Apr 2025 20:11:05 +0800 Subject: [PATCH] Add dynamic category part. --- lib/foundation/comic_source/category.dart | 37 +++++++++++++++++++++++ lib/foundation/comic_source/parser.dart | 25 +++++++++++---- lib/pages/category_comics_page.dart | 3 ++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/lib/foundation/comic_source/category.dart b/lib/foundation/comic_source/category.dart index 1ade4e0..a27e247 100644 --- a/lib/foundation/comic_source/category.dart +++ b/lib/foundation/comic_source/category.dart @@ -97,6 +97,43 @@ class RandomCategoryPart extends BaseCategoryPart { ); } +class DynamicCategoryPart extends BaseCategoryPart { + final JSAutoFreeFunction loader; + + final String sourceKey; + + @override + List get categories { + var data = loader([]); + print(data); + if (data is! List) { + throw "DynamicCategoryPart loader must return a List"; + } + var res = []; + for (var item in data) { + if (item is! Map) { + throw "DynamicCategoryPart loader must return a List of Map"; + } + var label = item['label']; + var target = PageJumpTarget.parse(sourceKey, item['target']); + if (label is! String) { + throw "Category label must be a String"; + } + res.add(CategoryItem(label, target)); + } + return res; + } + + @override + bool get enableRandom => false; + + @override + final String title; + + /// A [BaseCategoryPart] that show dynamic tags on category page. + const DynamicCategoryPart(this.title, this.loader, this.sourceKey); +} + CategoryData getCategoryDataWithKey(String key) { for (var source in ComicSource.all()) { if (source.categoryData?.key == key) { diff --git a/lib/foundation/comic_source/parser.dart b/lib/foundation/comic_source/parser.dart index 6a2e590..0d92978 100644 --- a/lib/foundation/comic_source/parser.dart +++ b/lib/foundation/comic_source/parser.dart @@ -403,27 +403,40 @@ class ComicSourceParser { var categoryParts = []; for (var c in doc["parts"]) { - if (c["categories"] is! List || c["categories"].isEmpty) { + if (c["categories"] != null && c["categories"] is! List) { continue; } - List categories = c["categories"]; - if (categories[0] is Map) { + List? categories = c["categories"]; + if (categories == null || categories[0] is Map) { // new format final String name = c["name"]; final String type = c["type"]; final cs = categories - .map( + ?.map( (e) => CategoryItem( e['label'], PageJumpTarget.parse(_key!, e['target']), ), ) .toList(); + if (type != "dynamic" && (cs == null || cs.isEmpty)) { + continue; + } if (type == "fixed") { - categoryParts.add(FixedCategoryPart(name, cs)); + categoryParts.add(FixedCategoryPart(name, cs!)); } else if (type == "random") { categoryParts - .add(RandomCategoryPart(name, cs, c["randomNumber"] ?? 1)); + .add(RandomCategoryPart(name, cs!, c["randomNumber"] ?? 1)); + } else if (type == "dynamic" && categories == null) { + var loader = c["loader"]; + if (loader is! JSInvokable) { + throw "DynamicCategoryPart loader must be a function"; + } + categoryParts.add(DynamicCategoryPart( + name, + JSAutoFreeFunction(loader), + _key!, + )); } } else { // old format diff --git a/lib/pages/category_comics_page.dart b/lib/pages/category_comics_page.dart index a8840d6..f29aaaf 100644 --- a/lib/pages/category_comics_page.dart +++ b/lib/pages/category_comics_page.dart @@ -34,6 +34,9 @@ class _CategoryComicsPageState extends State { void findData() { for (final source in ComicSource.all()) { if (source.categoryData?.key == widget.categoryKey) { + if (source.categoryComicsData == null) { + throw "The comic source ${source.name} does not support category comics"; + } data = source.categoryComicsData!; options = data.options.where((element) { if (element.notShowWhen.contains(widget.category)) {