Add buttons for adding pages

This commit is contained in:
2025-01-25 12:23:30 +08:00
parent bab2578b65
commit 812b36d1e9
4 changed files with 202 additions and 102 deletions

View File

@@ -269,12 +269,19 @@ class _MySliverAppBarDelegate extends SliverPersistentHeaderDelegate {
} }
class AppTabBar extends StatefulWidget { class AppTabBar extends StatefulWidget {
const AppTabBar({super.key, this.controller, required this.tabs}); const AppTabBar({
super.key,
this.controller,
required this.tabs,
this.actionButton,
});
final TabController? controller; final TabController? controller;
final List<Tab> tabs; final List<Tab> tabs;
final Widget? actionButton;
@override @override
State<AppTabBar> createState() => _AppTabBarState(); State<AppTabBar> createState() => _AppTabBarState();
} }
@@ -378,7 +385,8 @@ class _AppTabBarState extends State<AppTabBar> {
painter: painter, painter: painter,
child: _TabRow( child: _TabRow(
callback: _tabLayoutCallback, callback: _tabLayoutCallback,
children: List.generate(widget.tabs.length, buildTab), children: List.generate(widget.tabs.length, buildTab)
..addIfNotNull(widget.actionButton?.padding(tabPadding)),
), ),
).paddingHorizontal(4), ).paddingHorizontal(4),
); );
@@ -396,7 +404,8 @@ class _AppTabBarState extends State<AppTabBar> {
), ),
), ),
), ),
child: widget.tabs.isEmpty ? const SizedBox() : child); child: widget.tabs.isEmpty ? const SizedBox() : child,
);
} }
int? previousIndex; int? previousIndex;
@@ -633,7 +642,6 @@ class _TabViewBodyState extends State<TabViewBody> {
} }
} }
class SearchBarController { class SearchBarController {
_SearchBarMixin? _state; _SearchBarMixin? _state;
@@ -906,3 +914,42 @@ class _SearchBarState extends State<AppSearchBar> with _SearchBarMixin {
); );
} }
} }
class TabActionButton extends StatelessWidget {
const TabActionButton({
super.key,
required this.icon,
required this.text,
required this.onPressed,
});
final Icon icon;
final String text;
final void Function() onPressed;
static const _kTabHeight = 46.0;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(8),
child: Container(
height: _kTabHeight,
padding: const EdgeInsets.symmetric(horizontal: 12),
child: IconTheme(
data: IconThemeData(size: 20, color: context.colorScheme.primary),
child: Row(
children: [
icon,
const SizedBox(width: 8),
Text(text, style: ts.withColor(context.colorScheme.primary)),
],
),
),
),
);
}
}

View File

@@ -3,36 +3,72 @@ import 'package:venera/components/components.dart';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/appdata.dart'; import 'package:venera/foundation/appdata.dart';
import 'package:venera/foundation/comic_source/comic_source.dart'; import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/state_controller.dart';
import 'package:venera/pages/ranking_page.dart'; import 'package:venera/pages/ranking_page.dart';
import 'package:venera/pages/search_result_page.dart'; import 'package:venera/pages/search_result_page.dart';
import 'package:venera/pages/settings/settings_page.dart';
import 'package:venera/utils/ext.dart';
import 'package:venera/utils/translations.dart'; import 'package:venera/utils/translations.dart';
import 'category_comics_page.dart'; import 'category_comics_page.dart';
class CategoriesPage extends StatelessWidget { class CategoriesPage extends StatefulWidget {
const CategoriesPage({super.key}); const CategoriesPage({super.key});
@override @override
Widget build(BuildContext context) { State<CategoriesPage> createState() => _CategoriesPageState();
return StateBuilder<SimpleController>( }
tag: "category",
init: SimpleController(), class _CategoriesPageState extends State<CategoriesPage> {
builder: (controller) { var categories = <String>[];
var categories = List.from(appdata.settings["categories"]);
void onSettingsChanged() {
var categories =
List.from(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 =
.where((element) => allCategories.contains(element)) categories.where((element) => allCategories.contains(element)).toList();
.toList(); if (!categories.isEqualsTo(this.categories)) {
setState(() {
this.categories = categories;
});
}
}
if(categories.isEmpty) { @override
void initState() {
super.initState();
var categories =
List.from(appdata.settings["categories"]).whereType<String>().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();
appdata.settings.addListener(onSettingsChanged);
}
void addPage() {
showPopUpWidget(App.rootContext, setCategoryPagesWidget());
}
@override
void dispose() {
super.dispose();
appdata.settings.removeListener(onSettingsChanged);
}
@override
Widget build(BuildContext context) {
if (categories.isEmpty) {
var msg = "No Category Pages".tl; var msg = "No Category Pages".tl;
msg += '\n'; msg += '\n';
if(ComicSource.isEmpty) { if (ComicSource.isEmpty) {
msg += "Add a comic source in home page".tl; msg += "Add a comic source in home page".tl;
} else { } else {
msg += "Please check your settings".tl; msg += "Please check your settings".tl;
@@ -40,7 +76,7 @@ class CategoriesPage extends StatelessWidget {
return NetworkError( return NetworkError(
message: msg, message: msg,
retry: () { retry: () {
controller.update(); setState(() {});
}, },
withAppbar: false, withAppbar: false,
); );
@@ -66,18 +102,21 @@ class CategoriesPage extends StatelessWidget {
key: Key(e), key: Key(e),
); );
}).toList(), }).toList(),
actionButton: TabActionButton(
icon: const Icon(Icons.add),
text: "Add".tl,
onPressed: addPage,
),
).paddingTop(context.padding.top), ).paddingTop(context.padding.top),
Expanded( Expanded(
child: TabBarView( child: TabBarView(
children: children: categories.map((e) => _CategoryPage(e)).toList(),
categories.map((e) => _CategoryPage(e)).toList()), ),
) )
], ],
), ),
), ),
); );
},
);
} }
} }

View File

@@ -6,6 +6,7 @@ import 'package:venera/foundation/comic_source/comic_source.dart';
import 'package:venera/foundation/res.dart'; import 'package:venera/foundation/res.dart';
import 'package:venera/foundation/state_controller.dart'; import 'package:venera/foundation/state_controller.dart';
import 'package:venera/pages/search_result_page.dart'; import 'package:venera/pages/search_result_page.dart';
import 'package:venera/pages/settings/settings_page.dart';
import 'package:venera/utils/ext.dart'; import 'package:venera/utils/ext.dart';
import 'package:venera/utils/translations.dart'; import 'package:venera/utils/translations.dart';
@@ -56,6 +57,10 @@ class _ExplorePageState extends State<ExplorePage>
} }
} }
void addPage() {
showPopUpWidget(App.rootContext, setExplorePagesWidget());
}
NaviPaneState? naviPane; NaviPaneState? naviPane;
@override @override
@@ -141,6 +146,11 @@ class _ExplorePageState extends State<ExplorePage>
key: PageStorageKey(pages.toString()), key: PageStorageKey(pages.toString()),
tabs: pages.map((e) => buildTab(e)).toList(), tabs: pages.map((e) => buildTab(e)).toList(),
controller: controller, controller: controller,
actionButton: TabActionButton(
icon: const Icon(Icons.add),
text: "Add".tl,
onPressed: addPage,
),
), ),
).paddingTop(context.padding.top); ).paddingTop(context.padding.top);

View File

@@ -30,35 +30,11 @@ class _ExploreSettingsState extends State<ExploreSettings> {
).toSliver(), ).toSliver(),
_PopupWindowSetting( _PopupWindowSetting(
title: "Explore Pages".tl, title: "Explore Pages".tl,
builder: () { builder: setExplorePagesWidget,
var pages = <String, String>{};
for (var c in ComicSource.all()) {
for (var page in c.explorePages) {
pages[page.title] = page.title;
}
}
return _MultiPagesFilter(
title: "Explore Pages".tl,
settingsIndex: "explore_pages",
pages: pages,
);
},
).toSliver(), ).toSliver(),
_PopupWindowSetting( _PopupWindowSetting(
title: "Category Pages".tl, title: "Category Pages".tl,
builder: () { builder: setCategoryPagesWidget,
var pages = <String, String>{};
for (var c in ComicSource.all()) {
if (c.categoryData != null) {
pages[c.categoryData!.key] = c.categoryData!.title;
}
}
return _MultiPagesFilter(
title: "Category Pages".tl,
settingsIndex: "categories",
pages: pages,
);
},
).toSliver(), ).toSliver(),
_PopupWindowSetting( _PopupWindowSetting(
title: "Network Favorite Pages".tl, title: "Network Favorite Pages".tl,
@@ -205,3 +181,31 @@ class _ManageBlockingWordViewState extends State<_ManageBlockingWordView> {
); );
} }
} }
Widget setExplorePagesWidget() {
var pages = <String, String>{};
for (var c in ComicSource.all()) {
for (var page in c.explorePages) {
pages[page.title] = page.title;
}
}
return _MultiPagesFilter(
title: "Explore Pages".tl,
settingsIndex: "explore_pages",
pages: pages,
);
}
Widget setCategoryPagesWidget() {
var pages = <String, String>{};
for (var c in ComicSource.all()) {
if (c.categoryData != null) {
pages[c.categoryData!.key] = c.categoryData!.title;
}
}
return _MultiPagesFilter(
title: "Category Pages".tl,
settingsIndex: "categories",
pages: pages,
);
}