diff --git a/lib/components/loading.dart b/lib/components/loading.dart index 31035da..73d896c 100644 --- a/lib/components/loading.dart +++ b/lib/components/loading.dart @@ -152,6 +152,7 @@ abstract class MultiPageLoadingState void firstLoad() { loadData(_page).then((value) { + if (!mounted) return; if(value.success) { _page++; setState(() { diff --git a/lib/network/novel.dart b/lib/network/novel.dart index 4c987dc..43f3072 100644 --- a/lib/network/novel.dart +++ b/lib/network/novel.dart @@ -35,15 +35,15 @@ extension NovelExt on Network { return getNovelsWithNextUrl(url); } - Future>> getBookmarkedNovels(String uid) { + Future>> getBookmarkedNovels(String uid, bool public) { return getNovelsWithNextUrl( - "/v1/user/bookmarks/novel?user_id=$uid&restrict=public"); + "/v1/user/bookmarks/novel?user_id=$uid&restrict=${public ? "public" : "private"}"); } - Future> favoriteNovel(String id) async { + Future> favoriteNovel(String id, bool public) async { var res = await apiPost("/v2/novel/bookmark/add", data: { "novel_id": id, - "restrict": "public", + "restrict": public ? "public" : "private", }); if (res.error) { return Res.fromErrorRes(res); diff --git a/lib/pages/novel_bookmarks_page.dart b/lib/pages/novel_bookmarks_page.dart index 6ad9772..e8e8ce2 100644 --- a/lib/pages/novel_bookmarks_page.dart +++ b/lib/pages/novel_bookmarks_page.dart @@ -3,6 +3,7 @@ import 'package:pixes/appdata.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'; @@ -17,11 +18,41 @@ class NovelBookmarksPage extends StatefulWidget { class _NovelBookmarksPageState extends MultiPageLoadingState { + bool public = true; + + @override + Widget? buildFrame(BuildContext context, Widget child) { + return Column( + children: [ + TitleBar( + title: "Bookmarks".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: [ - TitleBar(title: "Bookmarks".tl), Expanded( child: GridViewWithFixedItemHeight( itemCount: data.length, @@ -45,7 +76,7 @@ class _NovelBookmarksPageState Future>> loadData(int page) async { if (nextUrl == "end") return Res.error("No more data"); var res = nextUrl == null - ? await Network().getBookmarkedNovels(appdata.account!.user.id) + ? await Network().getBookmarkedNovels(appdata.account!.user.id, public) : await Network().getNovelsWithNextUrl(nextUrl!); nextUrl = res.subData ?? "end"; return res; diff --git a/lib/pages/novel_page.dart b/lib/pages/novel_page.dart index 3688d7c..06cc0f0 100644 --- a/lib/pages/novel_page.dart +++ b/lib/pages/novel_page.dart @@ -121,18 +121,18 @@ class _NovelPageState extends State { padding: const EdgeInsets.only(bottom: 10), child: Row( children: [ - const SizedBox( - width: 2, - ), + const SizedBox(width: 2), Expanded( child: Container( height: 68, decoration: BoxDecoration( - border: Border.all( - color: ColorScheme.of(context).outlineVariant, - width: 0.6), - borderRadius: BorderRadius.circular(4)), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + border: Border.all( + color: ColorScheme.of(context).outlineVariant, + width: 0.6, + ), + borderRadius: BorderRadius.circular(4), + ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: Row( children: [ Column( @@ -148,31 +148,31 @@ class _NovelPageState extends State { ) ], ), - const SizedBox( - width: 12, - ), + const SizedBox(width: 8), Text( widget.novel.totalViews.toString(), style: TextStyle( - color: ColorScheme.of(context).primary, - fontWeight: FontWeight.w500, - fontSize: 18), + color: ColorScheme.of(context).primary, + fontWeight: FontWeight.w500, + fontSize: 18, + ), ) ], ), ), ), - const SizedBox( - width: 16, - ), + const SizedBox(width: 16), Expanded( child: Container( height: 68, decoration: BoxDecoration( - border: Border.all( - color: ColorScheme.of(context).outlineVariant, width: 0.6), - borderRadius: BorderRadius.circular(4)), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + border: Border.all( + color: ColorScheme.of(context).outlineVariant, + width: 0.6, + ), + borderRadius: BorderRadius.circular(4), + ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: Row( children: [ Column( @@ -188,22 +188,19 @@ class _NovelPageState extends State { ) ], ), - const SizedBox( - width: 12, - ), + const SizedBox(width: 8), Text( widget.novel.totalBookmarks.toString(), style: TextStyle( - color: ColorScheme.of(context).primary, - fontWeight: FontWeight.w500, - fontSize: 18), + color: ColorScheme.of(context).primary, + fontWeight: FontWeight.w500, + fontSize: 18, + ), ) ], ), )), - const SizedBox( - width: 2, - ), + const SizedBox(width: 2), ], ), ); @@ -241,25 +238,30 @@ class _NovelPageState extends State { ), ), const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(widget.novel.author.name, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + widget.novel.author.name, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - )), - Text( - widget.novel.createDate.toString().substring(0, 10), - style: TextStyle( - fontSize: 12, - color: ColorScheme.of(context).outline, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - ), - ], + Text( + widget.novel.createDate.toString().substring(0, 10), + style: TextStyle( + fontSize: 12, + color: ColorScheme.of(context).outline, + ), + ), + ], + ), ), - const Spacer(), const Icon(MdIcons.chevron_right) ], ), @@ -271,15 +273,43 @@ class _NovelPageState extends State { bool isAddingFavorite = false; + var favoriteFlyout = FlyoutController(); + Widget buildActions() { void favorite() async { if (isAddingFavorite) return; + bool? public; + if (!widget.novel.isBookmarked) { + await favoriteFlyout.showFlyout( + builder: (context) { + return MenuFlyout( + items: [ + MenuFlyoutItem( + text: Text("Public".tl), + onPressed: () { + public = true; + }, + ), + MenuFlyoutItem( + text: Text("Private".tl), + onPressed: () { + public = false; + }, + ), + ], + ); + }, + ); + if (public == null) { + return; + } + } setState(() { isAddingFavorite = true; }); var res = widget.novel.isBookmarked ? await Network().deleteFavoriteNovel(widget.novel.id.toString()) - : await Network().favoriteNovel(widget.novel.id.toString()); + : await Network().favoriteNovel(widget.novel.id.toString(), public!); if (res.error) { if (mounted) { context.showToast(message: res.errorMessage ?? "Network Error"); @@ -337,38 +367,41 @@ class _NovelPageState extends State { context.to(() => NovelReadingPage(widget.novel)); }), const SizedBox(width: 16), - Button( - onPressed: favorite, - child: Row( - mainAxisAlignment: constrains.maxWidth > 420 - ? MainAxisAlignment.start - : MainAxisAlignment.center, - children: [ - if (isAddingFavorite) - const SizedBox( - width: 18, - height: 18, - child: ProgressRing( - strokeWidth: 2, - ), - ) - else if (widget.novel.isBookmarked) - Icon( - MdIcons.favorite, - size: 18, - color: ColorScheme.of(context).error, - ) - else - const Icon(MdIcons.favorite_outline, size: 18), - if (constrains.maxWidth > 420) - const SizedBox(width: 12), - if (constrains.maxWidth > 420) Text("Favorite".tl) - ], - ) - .fixWidth(shouldFillSpace - ? width / 4 - 4 - kFluentButtonPadding - : 64) - .fixHeight(32), + FlyoutTarget( + controller: favoriteFlyout, + child: Button( + onPressed: favorite, + child: Row( + mainAxisAlignment: constrains.maxWidth > 420 + ? MainAxisAlignment.start + : MainAxisAlignment.center, + children: [ + if (isAddingFavorite) + const SizedBox( + width: 18, + height: 18, + child: ProgressRing( + strokeWidth: 2, + ), + ) + else if (widget.novel.isBookmarked) + Icon( + MdIcons.favorite, + size: 18, + color: ColorScheme.of(context).error, + ) + else + const Icon(MdIcons.favorite_outline, size: 18), + if (constrains.maxWidth > 420) + const SizedBox(width: 12), + if (constrains.maxWidth > 420) Text("Favorite".tl) + ], + ) + .fixWidth(shouldFillSpace + ? width / 4 - 4 - kFluentButtonPadding + : 64) + .fixHeight(32), + ), ), const SizedBox(width: 8), Button(