mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 15:57:25 +00:00
fix #52
This commit is contained in:
@@ -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(),
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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>{
|
||||||
|
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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()
|
||||||
|
Reference in New Issue
Block a user