diff --git a/lib/network/novel.dart b/lib/network/novel.dart index 43f3072..5e39b22 100644 --- a/lib/network/novel.dart +++ b/lib/network/novel.dart @@ -149,4 +149,17 @@ extension NovelExt on Network { } return Res(Novel.fromJson(res.data["novel"])); } + + Future>> getFollowingNovels(String restrict, + [String? nextUrl]) async { + var res = await apiGet(nextUrl ?? "/v1/novel/follow?restrict=$restrict"); + if (res.success) { + return Res( + (res.data["novels"] as List).map((e) => Novel.fromJson(e)).toList(), + subData: res.data["next_url"], + ); + } else { + return Res.error(res.errorMessage); + } + } } diff --git a/lib/pages/following_novels_page.dart b/lib/pages/following_novels_page.dart new file mode 100644 index 0000000..9c425ab --- /dev/null +++ b/lib/pages/following_novels_page.dart @@ -0,0 +1,83 @@ +import 'package:fluent_ui/fluent_ui.dart'; +import 'package:pixes/components/grid.dart'; +import 'package:pixes/components/loading.dart'; +import 'package:pixes/components/novel.dart'; +import 'package:pixes/components/segmented_button.dart'; +import 'package:pixes/components/title_bar.dart'; +import 'package:pixes/foundation/widget_utils.dart'; +import 'package:pixes/network/network.dart'; +import 'package:pixes/utils/translation.dart'; + +class FollowingNovelsPage extends StatefulWidget { + const FollowingNovelsPage({super.key}); + + @override + State createState() => _FollowingNovelsPageState(); +} + +class _FollowingNovelsPageState + extends MultiPageLoadingState { + bool public = true; + + @override + Widget? buildFrame(BuildContext context, Widget child) { + return Column( + children: [ + TitleBar( + title: "Following".tl, + action: SegmentedButton( + options: [ + SegmentedButtonOption("public", "Public".tl), + SegmentedButtonOption("private", "Private".tl), + ], + onPressed: (key) { + var newPublic = key == "public"; + if (newPublic != public) { + public = newPublic; + nextUrl = null; + reset(); + } + }, + value: public ? "public" : "private", + ), + ), + Expanded( + child: child, + ) + ], + ); + } + + @override + Widget buildContent(BuildContext context, List data) { + return Column( + children: [ + Expanded( + child: GridViewWithFixedItemHeight( + itemCount: data.length, + itemHeight: 164, + minCrossAxisExtent: 400, + builder: (context, index) { + if (index == data.length - 1) { + nextPage(); + } + return NovelWidget(data[index]); + }, + ).paddingHorizontal(8), + ) + ], + ); + } + + String? nextUrl; + + @override + Future>> loadData(int page) async { + if (nextUrl == "end") return Res.error("No more data"); + var res = nextUrl == null + ? await Network().getFollowingNovels(public ? "public" : "private") + : await Network().getNovelsWithNextUrl(nextUrl!); + nextUrl = res.subData ?? "end"; + return res; + } +} diff --git a/lib/pages/main_page.dart b/lib/pages/main_page.dart index ece1d6e..a6b9cdb 100644 --- a/lib/pages/main_page.dart +++ b/lib/pages/main_page.dart @@ -11,6 +11,7 @@ import "package:pixes/network/network.dart"; import "package:pixes/pages/bookmarks.dart"; import "package:pixes/pages/downloaded_page.dart"; import "package:pixes/pages/following_artworks.dart"; +import "package:pixes/pages/following_novels_page.dart"; import "package:pixes/pages/history.dart"; import "package:pixes/pages/novel_bookmarks_page.dart"; import "package:pixes/pages/novel_ranking_page.dart"; @@ -213,6 +214,11 @@ class _MainPageState extends State title: Text('Bookmarks'.tl), body: const SizedBox.shrink(), ), + PaneItem( + icon: const Icon(MdIcons.interests_outlined, size: 20), + title: Text('Following'.tl), + body: const SizedBox.shrink(), + ), PaneItem( icon: const Icon(MdIcons.leaderboard_outlined, size: 20), title: Text('Ranking'.tl), @@ -253,6 +259,7 @@ class _MainPageState extends State () => const RankingPage(), () => const NovelRecommendationPage(), () => const NovelBookmarksPage(), + () => const FollowingNovelsPage(), () => const NovelRankingPage(), () => const SettingsPage(), ];