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 {
const AppTabBar({super.key, this.controller, required this.tabs});
const AppTabBar({
super.key,
this.controller,
required this.tabs,
this.actionButton,
});
final TabController? controller;
final List<Tab> tabs;
final Widget? actionButton;
@override
State<AppTabBar> createState() => _AppTabBarState();
}
@@ -378,7 +385,8 @@ class _AppTabBarState extends State<AppTabBar> {
painter: painter,
child: _TabRow(
callback: _tabLayoutCallback,
children: List.generate(widget.tabs.length, buildTab),
children: List.generate(widget.tabs.length, buildTab)
..addIfNotNull(widget.actionButton?.padding(tabPadding)),
),
).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;
@@ -633,7 +642,6 @@ class _TabViewBodyState extends State<TabViewBody> {
}
}
class SearchBarController {
_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,32 +3,68 @@ import 'package:venera/components/components.dart';
import 'package:venera/foundation/app.dart';
import 'package:venera/foundation/appdata.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/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 'category_comics_page.dart';
class CategoriesPage extends StatelessWidget {
class CategoriesPage extends StatefulWidget {
const CategoriesPage({super.key});
@override
Widget build(BuildContext context) {
return StateBuilder<SimpleController>(
tag: "category",
init: SimpleController(),
builder: (controller) {
var categories = List.from(appdata.settings["categories"]);
State<CategoriesPage> createState() => _CategoriesPageState();
}
class _CategoriesPageState extends State<CategoriesPage> {
var categories = <String>[];
void onSettingsChanged() {
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();
categories = categories
.where((element) => allCategories.contains(element))
.toList();
categories =
categories.where((element) => allCategories.contains(element)).toList();
if (!categories.isEqualsTo(this.categories)) {
setState(() {
this.categories = categories;
});
}
}
@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;
msg += '\n';
@@ -40,7 +76,7 @@ class CategoriesPage extends StatelessWidget {
return NetworkError(
message: msg,
retry: () {
controller.update();
setState(() {});
},
withAppbar: false,
);
@@ -66,18 +102,21 @@ class CategoriesPage extends StatelessWidget {
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()),
children: 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/state_controller.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';
@@ -56,6 +57,10 @@ class _ExplorePageState extends State<ExplorePage>
}
}
void addPage() {
showPopUpWidget(App.rootContext, setExplorePagesWidget());
}
NaviPaneState? naviPane;
@override
@@ -141,6 +146,11 @@ class _ExplorePageState extends State<ExplorePage>
key: PageStorageKey(pages.toString()),
tabs: pages.map((e) => buildTab(e)).toList(),
controller: controller,
actionButton: TabActionButton(
icon: const Icon(Icons.add),
text: "Add".tl,
onPressed: addPage,
),
),
).paddingTop(context.padding.top);

View File

@@ -30,35 +30,11 @@ class _ExploreSettingsState extends State<ExploreSettings> {
).toSliver(),
_PopupWindowSetting(
title: "Explore Pages".tl,
builder: () {
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,
);
},
builder: setExplorePagesWidget,
).toSliver(),
_PopupWindowSetting(
title: "Category Pages".tl,
builder: () {
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,
);
},
builder: setCategoryPagesWidget,
).toSliver(),
_PopupWindowSetting(
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,
);
}