mirror of
https://github.com/venera-app/venera.git
synced 2025-09-27 07:47:24 +00:00
Use PageStorage to store state
This commit is contained in:
@@ -53,6 +53,7 @@ class CategoriesPage extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
FilledTabBar(
|
||||
key: PageStorageKey(categories.toString()),
|
||||
tabs: categories.map((e) {
|
||||
String title = e;
|
||||
try {
|
||||
|
@@ -110,7 +110,7 @@ class _ExplorePageState extends State<ExplorePage>
|
||||
return Tab(text: i.ts(comicSource.key), key: Key(i));
|
||||
}
|
||||
|
||||
Widget buildBody(String i) => _SingleExplorePage(i, key: Key(i));
|
||||
Widget buildBody(String i) => _SingleExplorePage(i, key: PageStorageKey(i));
|
||||
|
||||
Widget buildEmpty() {
|
||||
var msg = "No Explore Pages".tl;
|
||||
@@ -147,7 +147,7 @@ class _ExplorePageState extends State<ExplorePage>
|
||||
|
||||
Widget tabBar = Material(
|
||||
child: FilledTabBar(
|
||||
key: Key(pages.toString()),
|
||||
key: PageStorageKey(pages.toString()),
|
||||
tabs: pages.map((e) => buildTab(e)).toList(),
|
||||
controller: controller,
|
||||
),
|
||||
@@ -240,12 +240,6 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
|
||||
with AutomaticKeepAliveClientMixin<_SingleExplorePage> {
|
||||
late final ExplorePageData data;
|
||||
|
||||
bool loading = true;
|
||||
|
||||
String? message;
|
||||
|
||||
List<ExplorePagePart>? parts;
|
||||
|
||||
late final String comicSourceKey;
|
||||
|
||||
int key = 0;
|
||||
@@ -288,9 +282,19 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
if (data.loadMultiPart != null) {
|
||||
return buildMultiPart();
|
||||
return _MultiPartExplorePage(
|
||||
key: PageStorageKey(key),
|
||||
data: data,
|
||||
controller: scrollController,
|
||||
comicSourceKey: comicSourceKey,
|
||||
);
|
||||
} else if (data.loadPage != null || data.loadNext != null) {
|
||||
return buildComicList();
|
||||
return ComicList(
|
||||
loadPage: data.loadPage,
|
||||
loadNext: data.loadNext,
|
||||
key: PageStorageKey(key),
|
||||
controller: scrollController,
|
||||
);
|
||||
} else if (data.loadMixed != null) {
|
||||
return _MixedExplorePage(
|
||||
data,
|
||||
@@ -305,74 +309,14 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildComicList() {
|
||||
return ComicList(
|
||||
loadPage: data.loadPage,
|
||||
loadNext: data.loadNext,
|
||||
key: ValueKey(key),
|
||||
controller: scrollController,
|
||||
);
|
||||
}
|
||||
|
||||
void load() async {
|
||||
var res = await data.loadMultiPart!();
|
||||
loading = false;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
if (res.error) {
|
||||
message = res.errorMessage;
|
||||
} else {
|
||||
parts = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildMultiPart() {
|
||||
if (loading) {
|
||||
load();
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else if (message != null) {
|
||||
return NetworkError(
|
||||
message: message!,
|
||||
retry: refresh,
|
||||
withAppbar: false,
|
||||
);
|
||||
} else {
|
||||
return buildPage();
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildPage() {
|
||||
return SmoothCustomScrollView(
|
||||
controller: scrollController,
|
||||
slivers: _buildPage().toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Iterable<Widget> _buildPage() sync* {
|
||||
for (var part in parts!) {
|
||||
yield* _buildExplorePagePart(part, comicSourceKey);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Object? get tag => widget.title;
|
||||
|
||||
@override
|
||||
void refresh() {
|
||||
message = null;
|
||||
if (data.loadMultiPart != null) {
|
||||
setState(() {
|
||||
loading = true;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
key++;
|
||||
});
|
||||
}
|
||||
setState(() {
|
||||
key++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -393,7 +337,8 @@ class _SingleExplorePageState extends StateWithController<_SingleExplorePage>
|
||||
}
|
||||
|
||||
class _MixedExplorePage extends StatefulWidget {
|
||||
const _MixedExplorePage(this.data, this.sourceKey, {super.key, this.controller});
|
||||
const _MixedExplorePage(this.data, this.sourceKey,
|
||||
{super.key, this.controller});
|
||||
|
||||
final ExplorePageData data;
|
||||
|
||||
@@ -518,3 +463,112 @@ Iterable<Widget> _buildExplorePagePart(
|
||||
yield buildTitle(part);
|
||||
yield buildComics(part);
|
||||
}
|
||||
|
||||
class _MultiPartExplorePage extends StatefulWidget {
|
||||
const _MultiPartExplorePage({
|
||||
super.key,
|
||||
required this.data,
|
||||
required this.controller,
|
||||
required this.comicSourceKey,
|
||||
});
|
||||
|
||||
final ExplorePageData data;
|
||||
|
||||
final ScrollController controller;
|
||||
|
||||
final String comicSourceKey;
|
||||
|
||||
@override
|
||||
State<_MultiPartExplorePage> createState() => _MultiPartExplorePageState();
|
||||
}
|
||||
|
||||
class _MultiPartExplorePageState extends State<_MultiPartExplorePage> {
|
||||
late final ExplorePageData data;
|
||||
|
||||
List<ExplorePagePart>? parts;
|
||||
|
||||
bool loading = true;
|
||||
|
||||
String? message;
|
||||
|
||||
Map<String, dynamic> get state => {
|
||||
"loading": loading,
|
||||
"message": message,
|
||||
"parts": parts,
|
||||
};
|
||||
|
||||
void restoreState(dynamic state) {
|
||||
if (state == null) return;
|
||||
loading = state["loading"];
|
||||
message = state["message"];
|
||||
parts = state["parts"];
|
||||
}
|
||||
|
||||
void storeState() {
|
||||
PageStorage.of(context).writeState(context, state);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
data = widget.data;
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
restoreState(PageStorage.of(context).readState(context));
|
||||
}
|
||||
|
||||
void load() async {
|
||||
var res = await data.loadMultiPart!();
|
||||
loading = false;
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
if (res.error) {
|
||||
message = res.errorMessage;
|
||||
} else {
|
||||
parts = res.data;
|
||||
}
|
||||
});
|
||||
storeState();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (loading) {
|
||||
load();
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else if (message != null) {
|
||||
return NetworkError(
|
||||
message: message!,
|
||||
retry: () {
|
||||
setState(() {
|
||||
loading = true;
|
||||
message = null;
|
||||
});
|
||||
},
|
||||
withAppbar: false,
|
||||
);
|
||||
} else {
|
||||
return buildPage();
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildPage() {
|
||||
return SmoothCustomScrollView(
|
||||
key: const PageStorageKey('scroll'),
|
||||
controller: widget.controller,
|
||||
slivers: _buildPage().toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Iterable<Widget> _buildPage() sync* {
|
||||
for (var part in parts!) {
|
||||
yield* _buildExplorePagePart(part, widget.comicSourceKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -62,10 +62,18 @@ class _MainPageState extends State<MainPage> {
|
||||
}
|
||||
|
||||
final _pages = [
|
||||
const HomePage(),
|
||||
const FavoritesPage(),
|
||||
const ExplorePage(),
|
||||
const CategoriesPage(),
|
||||
const HomePage(
|
||||
key: PageStorageKey('home'),
|
||||
),
|
||||
const FavoritesPage(
|
||||
key: PageStorageKey('favorites'),
|
||||
),
|
||||
const ExplorePage(
|
||||
key: PageStorageKey('explore'),
|
||||
),
|
||||
const CategoriesPage(
|
||||
key: PageStorageKey('categories'),
|
||||
),
|
||||
];
|
||||
|
||||
var index = 0;
|
||||
|
Reference in New Issue
Block a user