This commit is contained in:
2024-11-30 21:36:23 +08:00
parent 2f4927f719
commit 30b2aa2f99
4 changed files with 85 additions and 11 deletions

View File

@@ -829,6 +829,7 @@ class ComicList extends StatefulWidget {
this.trailingSliver, this.trailingSliver,
this.errorLeading, this.errorLeading,
this.menuBuilder, this.menuBuilder,
this.controller,
}); });
final Future<Res<List<Comic>>> Function(int page)? loadPage; final Future<Res<List<Comic>>> Function(int page)? loadPage;
@@ -843,6 +844,8 @@ class ComicList extends StatefulWidget {
final List<MenuEntry> Function(Comic)? menuBuilder; final List<MenuEntry> Function(Comic)? menuBuilder;
final ScrollController? controller;
@override @override
State<ComicList> createState() => ComicListState(); State<ComicList> createState() => ComicListState();
} }
@@ -1064,6 +1067,7 @@ class ComicListState extends State<ComicList> {
); );
} }
return SmoothCustomScrollView( return SmoothCustomScrollView(
controller: widget.controller,
slivers: [ slivers: [
if (widget.leadingSliver != null) widget.leadingSliver!, if (widget.leadingSliver != null) widget.leadingSliver!,
if (_maxPage != 1) _buildSliverPageSelector(), if (_maxPage != 1) _buildSliverPageSelector(),

View File

@@ -47,10 +47,16 @@ class NaviPane extends StatefulWidget {
final GlobalKey<NavigatorState> navigatorKey; final GlobalKey<NavigatorState> navigatorKey;
@override @override
State<NaviPane> createState() => _NaviPaneState(); State<NaviPane> createState() => NaviPaneState();
static NaviPaneState of(BuildContext context) {
return context.findAncestorStateOfType<NaviPaneState>()!;
}
} }
class _NaviPaneState extends State<NaviPane> typedef NaviItemTapListener = void Function(int);
class NaviPaneState extends State<NaviPane>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late int _currentPage = widget.initialPage; late int _currentPage = widget.initialPage;
@@ -66,6 +72,16 @@ class _NaviPaneState extends State<NaviPane>
late AnimationController controller; late AnimationController controller;
final _naviItemTapListeners = <NaviItemTapListener>[];
void addNaviItemTapListener(NaviItemTapListener listener) {
_naviItemTapListeners.add(listener);
}
void removeNaviItemTapListener(NaviItemTapListener listener) {
_naviItemTapListeners.remove(listener);
}
static const _kBottomBarHeight = 58.0; static const _kBottomBarHeight = 58.0;
static const _kFoldedSideBarWidth = 80.0; static const _kFoldedSideBarWidth = 80.0;
@@ -85,9 +101,15 @@ class _NaviPaneState extends State<NaviPane>
} }
void updatePage(int index) { void updatePage(int index) {
for (var listener in _naviItemTapListeners) {
listener(index);
}
if (widget.observer.routes.length > 1) { if (widget.observer.routes.length > 1) {
widget.navigatorKey.currentState!.popUntil((route) => route.isFirst); widget.navigatorKey.currentState!.popUntil((route) => route.isFirst);
} }
if (currentPage == index) {
return;
}
setState(() { setState(() {
currentPage = index; currentPage = index;
}); });
@@ -670,14 +692,14 @@ class _NaviPopScope extends StatelessWidget {
class _NaviMainView extends StatefulWidget { class _NaviMainView extends StatefulWidget {
const _NaviMainView({required this.state}); const _NaviMainView({required this.state});
final _NaviPaneState state; final NaviPaneState state;
@override @override
State<_NaviMainView> createState() => _NaviMainViewState(); State<_NaviMainView> createState() => _NaviMainViewState();
} }
class _NaviMainViewState extends State<_NaviMainView> { class _NaviMainViewState extends State<_NaviMainView> {
_NaviPaneState get state => widget.state; NaviPaneState get state => widget.state;
@override @override
void initState() { void initState() {

View File

@@ -1,14 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class SimpleController extends StateController { class SimpleController extends StateController {
final void Function()? refresh_; final void Function()? refreshFunction;
SimpleController({this.refresh_}); final Map<String, dynamic> Function()? control;
SimpleController({this.refreshFunction, this.control});
@override @override
void refresh() { void refresh() {
(refresh_ ?? super.refresh)(); (refreshFunction ?? super.refresh)();
} }
Map<String, dynamic> get controlMap => control?.call() ?? {};
} }
abstract class StateController { abstract class StateController {
@@ -71,8 +75,8 @@ abstract class StateController {
static SimpleController putSimpleController( static SimpleController putSimpleController(
void Function() onUpdate, Object? tag, void Function() onUpdate, Object? tag,
{void Function()? refresh}) { {void Function()? refresh, Map<String, dynamic> Function()? control}) {
var controller = SimpleController(refresh_: refresh); var controller = SimpleController(refreshFunction: refresh, control: control);
controller.stateUpdaters.add(Pair(null, onUpdate)); controller.stateUpdaters.add(Pair(null, onUpdate));
_controllers.add(StateControllerWrapped(controller, false, tag)); _controllers.add(StateControllerWrapped(controller, false, tag));
return controller; return controller;
@@ -202,6 +206,7 @@ abstract class StateWithController<T extends StatefulWidget> extends State<T> {
}, },
tag, tag,
refresh: refresh, refresh: refresh,
control: () => control,
); );
super.initState(); super.initState();
} }
@@ -218,6 +223,8 @@ abstract class StateWithController<T extends StatefulWidget> extends State<T> {
} }
Object? get tag; Object? get tag;
Map<String, dynamic> get control => {};
} }
class Pair<M, V>{ class Pair<M, V>{

View File

@@ -46,6 +46,18 @@ class _ExplorePageState extends State<ExplorePage>
} }
} }
void onNaviItemTapped(int index) {
if (index == 2) {
int page = controller.index;
String currentPageId = pages[page];
StateController.find<SimpleController>(tag: currentPageId)
.control!()['toTop']
?.call();
}
}
NaviPaneState? naviPane;
@override @override
void initState() { void initState() {
pages = List<String>.from(appdata.settings["explore_pages"]); pages = List<String>.from(appdata.settings["explore_pages"]);
@@ -59,13 +71,21 @@ class _ExplorePageState extends State<ExplorePage>
vsync: this, vsync: this,
); );
appdata.settings.addListener(onSettingsChanged); appdata.settings.addListener(onSettingsChanged);
NaviPane.of(context).addNaviItemTapListener(onNaviItemTapped);
super.initState(); super.initState();
} }
@override
void didChangeDependencies() {
naviPane = NaviPane.of(context);
super.didChangeDependencies();
}
@override @override
void dispose() { void dispose() {
controller.dispose(); controller.dispose();
appdata.settings.removeListener(onSettingsChanged); appdata.settings.removeListener(onSettingsChanged);
naviPane?.removeNaviItemTapListener(onNaviItemTapped);
super.dispose(); super.dispose();
} }
@@ -95,7 +115,7 @@ class _ExplorePageState extends State<ExplorePage>
Widget buildEmpty() { Widget buildEmpty() {
var msg = "No Explore Pages".tl; var msg = "No Explore 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;
@@ -232,6 +252,8 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
bool _wantKeepAlive = true; bool _wantKeepAlive = true;
var scrollController = ScrollController();
void onSettingsChanged() { void onSettingsChanged() {
var explorePages = appdata.settings["explore_pages"]; var explorePages = appdata.settings["explore_pages"];
if (!explorePages.contains(widget.title)) { if (!explorePages.contains(widget.title)) {
@@ -274,6 +296,7 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
data, data,
comicSourceKey, comicSourceKey,
key: ValueKey(key), key: ValueKey(key),
controller: scrollController,
); );
} else { } else {
return const Center( return const Center(
@@ -287,6 +310,7 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
loadPage: data.loadPage, loadPage: data.loadPage,
loadNext: data.loadNext, loadNext: data.loadNext,
key: ValueKey(key), key: ValueKey(key),
controller: scrollController,
); );
} }
@@ -323,6 +347,7 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
Widget buildPage() { Widget buildPage() {
return SmoothCustomScrollView( return SmoothCustomScrollView(
controller: scrollController,
slivers: _buildPage().toList(), slivers: _buildPage().toList(),
); );
} }
@@ -352,15 +377,30 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
@override @override
bool get wantKeepAlive => _wantKeepAlive; bool get wantKeepAlive => _wantKeepAlive;
void toTop() {
if (scrollController.hasClients) {
scrollController.animateTo(
scrollController.position.minScrollExtent,
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
);
}
}
@override
Map<String, dynamic> get control => {"toTop": toTop};
} }
class _MixedExplorePage extends StatefulWidget { class _MixedExplorePage extends StatefulWidget {
const _MixedExplorePage(this.data, this.sourceKey, {super.key}); const _MixedExplorePage(this.data, this.sourceKey, {super.key, this.controller});
final ExplorePageData data; final ExplorePageData data;
final String sourceKey; final String sourceKey;
final ScrollController? controller;
@override @override
State<_MixedExplorePage> createState() => _MixedExplorePageState(); State<_MixedExplorePage> createState() => _MixedExplorePageState();
} }
@@ -394,6 +434,7 @@ class _MixedExplorePageState
@override @override
Widget buildContent(BuildContext context, List<Object> data) { Widget buildContent(BuildContext context, List<Object> data) {
return SmoothCustomScrollView( return SmoothCustomScrollView(
controller: widget.controller,
slivers: [ slivers: [
...buildSlivers(context, data), ...buildSlivers(context, data),
if (haveNextPage) const ListLoadingIndicator().toSliver() if (haveNextPage) const ListLoadingIndicator().toSliver()