Improve categories page.

This commit is contained in:
2025-10-13 20:28:03 +08:00
parent 3426d707fe
commit 49fd64358c

View File

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