From 49fd64358c07181ea700c52ab407422a03f7027d Mon Sep 17 00:00:00 2001 From: nyne Date: Mon, 13 Oct 2025 20:28:03 +0800 Subject: [PATCH] Improve categories page. --- lib/pages/categories_page.dart | 164 ++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 76 deletions(-) diff --git a/lib/pages/categories_page.dart b/lib/pages/categories_page.dart index 15ed457..953326a 100644 --- a/lib/pages/categories_page.dart +++ b/lib/pages/categories_page.dart @@ -17,39 +17,50 @@ class CategoriesPage extends StatefulWidget { State createState() => _CategoriesPageState(); } -class _CategoriesPageState extends State { +class _CategoriesPageState extends State + with + TickerProviderStateMixin, + AutomaticKeepAliveClientMixin { var categories = []; + late TabController controller; + void onSettingsChanged() { - var categories = - List.from(appdata.settings["categories"]).whereType().toList(); + var categories = List.from( + appdata.settings["categories"], + ).whereType().toList(); var allCategories = ComicSource.all() .map((e) => e.categoryData?.key) .where((element) => element != null) .map((e) => e!) .toList(); - categories = - categories.where((element) => allCategories.contains(element)).toList(); + categories = categories + .where((element) => allCategories.contains(element)) + .toList(); if (!categories.isEqualTo(this.categories)) { setState(() { this.categories = categories; }); + controller = TabController(length: categories.length, vsync: this); } } @override void initState() { super.initState(); - var categories = - List.from(appdata.settings["categories"]).whereType().toList(); + var categories = List.from( + appdata.settings["categories"], + ).whereType().toList(); var allCategories = ComicSource.all() .map((e) => e.categoryData?.key) .where((element) => element != null) .map((e) => e!) .toList(); - this.categories = - categories.where((element) => allCategories.contains(element)).toList(); + this.categories = categories + .where((element) => allCategories.contains(element)) + .toList(); appdata.settings.addListener(onSettingsChanged); + controller = TabController(length: categories.length, vsync: this); } void addPage() { @@ -59,6 +70,7 @@ class _CategoriesPageState extends State { @override void dispose() { super.dispose(); + controller.dispose(); appdata.settings.removeListener(onSettingsChanged); } @@ -85,46 +97,45 @@ class _CategoriesPageState extends State { @override Widget build(BuildContext context) { + super.build(context); if (categories.isEmpty) { return buildEmpty(); } return Material( - child: DefaultTabController( - length: categories.length, - key: Key(categories.toString()), - child: Column( - children: [ - AppTabBar( - key: PageStorageKey(categories.toString()), - tabs: categories.map((e) { - String title = e; - try { - title = getCategoryDataWithKey(e).title; - } catch (e) { - // - } - return Tab( - text: title, - key: Key(e), - ); - }).toList(), - actionButton: TabActionButton( - icon: const Icon(Icons.add), - text: "Add".tl, - onPressed: addPage, - ), - ).paddingTop(context.padding.top), - Expanded( - child: TabBarView( - children: categories.map((e) => _CategoryPage(e)).toList(), - ), - ) - ], - ), + child: Column( + children: [ + AppTabBar( + controller: controller, + key: PageStorageKey(categories.toString()), + tabs: categories.map((e) { + String title = e; + try { + title = getCategoryDataWithKey(e).title; + } catch (e) { + // + } + return Tab(text: title, key: Key(e)); + }).toList(), + actionButton: TabActionButton( + icon: const Icon(Icons.add), + text: "Add".tl, + onPressed: addPage, + ), + ).paddingTop(context.padding.top), + Expanded( + child: TabBarView( + controller: controller, + children: categories.map((e) => _CategoryPage(e)).toList(), + ), + ), + ], ), ); } + + @override + bool get wantKeepAlive => true; } typedef ClickTagCallback = void Function(String, String?); @@ -150,38 +161,42 @@ class _CategoryPage extends StatelessWidget { var children = []; if (data.enableRankingPage || data.buttons.isNotEmpty) { children.add(buildTitle(data.title)); - children.add(Padding( - padding: const EdgeInsets.fromLTRB(10, 0, 10, 16), - child: Wrap( - children: [ - if (data.enableRankingPage) - buildTag("Ranking".tl, () { - context.to(() => RankingPage(categoryKey: data.key)); - }), - for (var buttonData in data.buttons) - buildTag(buttonData.label.tl, buttonData.onTap) - ], + children.add( + Padding( + padding: const EdgeInsets.fromLTRB(10, 0, 10, 16), + child: Wrap( + children: [ + if (data.enableRankingPage) + buildTag("Ranking".tl, () { + context.to(() => RankingPage(categoryKey: data.key)); + }), + for (var buttonData in data.buttons) + buildTag(buttonData.label.tl, buttonData.onTap), + ], + ), ), - )); + ); } for (var part in data.categories) { if (part.enableRandom) { - children.add(StatefulBuilder(builder: (context, updater) { - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - buildTitleWithRefresh(part.title, () => updater(() {})), - buildTags(part.categories) - ], - ); - })); + children.add( + StatefulBuilder( + builder: (context, updater) { + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildTitleWithRefresh(part.title, () => updater(() {})), + buildTags(part.categories), + ], + ); + }, + ), + ); } else { children.add(buildTitle(part.title)); - children.add( - buildTags(part.categories), - ); + children.add(buildTags(part.categories)); } } return SingleChildScrollView( @@ -195,8 +210,10 @@ class _CategoryPage extends StatelessWidget { Widget buildTitle(String title) { return Padding( padding: const EdgeInsets.fromLTRB(16, 10, 5, 10), - child: Text(title.tl, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500)), + child: Text( + title.tl, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500), + ), ); } @@ -207,21 +224,16 @@ class _CategoryPage extends StatelessWidget { children: [ Text( title.tl, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.w500, - ), + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500), ), const Spacer(), - IconButton(onPressed: onRefresh, icon: const Icon(Icons.refresh)) + IconButton(onPressed: onRefresh, icon: const Icon(Icons.refresh)), ], ), ); } - Widget buildTags( - List categories, - ) { + Widget buildTags(List categories) { return Padding( padding: const EdgeInsets.fromLTRB(10, 0, 10, 16), child: Wrap(