From a8b0495fc6e9a6119998624b640a0c052bed849f Mon Sep 17 00:00:00 2001 From: wgh19 Date: Tue, 14 May 2024 22:15:05 +0800 Subject: [PATCH] load illust with id; context menu --- lib/components/illust_widget.dart | 154 +++++++++++++++++++----------- lib/network/download.dart | 1 + lib/network/network.dart | 9 ++ lib/pages/downloaded_page.dart | 23 +++-- lib/pages/illust_page.dart | 20 ++++ lib/pages/search_page.dart | 10 +- 6 files changed, 151 insertions(+), 66 deletions(-) diff --git a/lib/components/illust_widget.dart b/lib/components/illust_widget.dart index 61462cd..04857f3 100644 --- a/lib/components/illust_widget.dart +++ b/lib/components/illust_widget.dart @@ -2,6 +2,8 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:pixes/components/animated_image.dart'; import 'package:pixes/foundation/app.dart'; import 'package:pixes/foundation/image_provider.dart'; +import 'package:pixes/network/download.dart'; +import 'package:pixes/utils/translation.dart'; import '../network/network.dart'; import '../pages/illust_page.dart'; @@ -19,74 +21,118 @@ class IllustWidget extends StatefulWidget { class _IllustWidgetState extends State { bool isBookmarking = false; + final contextController = FlyoutController(); + final contextAttachKey = GlobalKey(); + @override Widget build(BuildContext context) { return LayoutBuilder(builder: (context, constrains) { final width = constrains.maxWidth; final height = widget.illust.height * width / widget.illust.width; - return SizedBox( - width: width, - height: height, - child: Stack( - children: [ - Positioned.fill(child: Container( - width: width, - height: height, - padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0), - child: Card( - padding: EdgeInsets.zero, - margin: EdgeInsets.zero, - child: GestureDetector( - onTap: (){ - context.to(() => IllustPage(widget.illust, favoriteCallback: (v) { - setState(() { - widget.illust.isBookmarked = v; - }); - },)); - }, - child: ClipRRect( - borderRadius: BorderRadius.circular(4.0), - child: AnimatedImage( - image: CachedImageProvider(widget.illust.images.first.medium), - fit: BoxFit.cover, - width: width-16.0, - height: height-16.0, + return FlyoutTarget( + controller: contextController, + child: SizedBox( + key: contextAttachKey, + width: width, + height: height, + child: Stack( + children: [ + Positioned.fill(child: Container( + width: width, + height: height, + padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0), + child: Card( + padding: EdgeInsets.zero, + margin: EdgeInsets.zero, + child: GestureDetector( + onTap: (){ + context.to(() => IllustPage(widget.illust, favoriteCallback: (v) { + setState(() { + widget.illust.isBookmarked = v; + }); + },)); + }, + onSecondaryTapUp: showMenu, + child: ClipRRect( + borderRadius: BorderRadius.circular(4.0), + child: AnimatedImage( + image: CachedImageProvider(widget.illust.images.first.medium), + fit: BoxFit.cover, + width: width-16.0, + height: height-16.0, + ), ), ), ), - ), - )), - Positioned( - top: 16, - right: 16, - child: buildButton(), - ) - ], + )), + Positioned( + top: 16, + right: 16, + child: buildButton(), + ) + ], + ), ), ); }); } - Widget buildButton() { - void favorite() async{ - if(isBookmarking) return; - setState(() { - isBookmarking = true; - }); - var method = widget.illust.isBookmarked ? "delete" : "add"; - var res = await Network().addBookmark(widget.illust.id.toString(), method); - if(res.error) { - if(mounted) { - context.showToast(message: "Network Error"); - } - } else { - widget.illust.isBookmarked = !widget.illust.isBookmarked; - } - setState(() { - isBookmarking = false; - }); - } + void showMenu(TapUpDetails details) { + // This calculates the position of the flyout according to the parent navigator + final targetContext = contextAttachKey.currentContext; + if (targetContext == null) return; + final box = targetContext.findRenderObject() as RenderBox; + final position = box.localToGlobal( + details.localPosition, + ancestor: Navigator.of(context).context.findRenderObject(), + ); + contextController.showFlyout( + barrierColor: Colors.transparent, + position: position, + builder: (context) { + return MenuFlyout( + items: [ + MenuFlyoutItem(text: Text("View".tl), onPressed: (){ + context.to(() => IllustPage(widget.illust, favoriteCallback: (v) { + setState(() { + widget.illust.isBookmarked = v; + }); + },)); + }), + MenuFlyoutItem(text: Text("Private Favorite".tl), onPressed: (){ + favorite("private"); + }), + MenuFlyoutItem(text: Text("Download".tl), onPressed: (){ + context.showToast(message: "Added"); + DownloadManager().addDownloadingTask(widget.illust); + }), + ], + ); + }, + ); + } + + void favorite([String type = "public"]) async{ + if(isBookmarking) return; + setState(() { + isBookmarking = true; + }); + var method = widget.illust.isBookmarked ? "delete" : "add"; + var res = await Network().addBookmark(widget.illust.id.toString(), method, type); + if(res.error) { + if(mounted) { + context.showToast(message: "Network Error"); + } + } else { + widget.illust.isBookmarked = !widget.illust.isBookmarked; + } + setState(() { + isBookmarking = false; + }); + } + + Widget buildButton() { Widget child; if(isBookmarking) { child = const SizedBox( diff --git a/lib/network/download.dart b/lib/network/download.dart index a3da621..c75be41 100644 --- a/lib/network/download.dart +++ b/lib/network/download.dart @@ -233,6 +233,7 @@ class DownloadManager { } void addDownloadingTask(Illust illust) { + if(illust.downloaded || illust.downloading) return; var task = DownloadingTask(illust, receiveBytesCallback: receiveBytes, onCompleted: (task) { saveInfo(illust, task.imagePaths); tasks.remove(task); diff --git a/lib/network/network.dart b/lib/network/network.dart index 0676170..8890364 100644 --- a/lib/network/network.dart +++ b/lib/network/network.dart @@ -391,4 +391,13 @@ class Network { return Res.fromErrorRes(res); } } + + Future> getIllustByID(String id) async { + var res = await apiGet("/v1/illust/detail?illust_id=$id"); + if (res.success) { + return Res(Illust.fromJson(res.data["illust"])); + } else { + return Res.error(res.errorMessage); + } + } } diff --git a/lib/pages/downloaded_page.dart b/lib/pages/downloaded_page.dart index d5fea2c..33be98e 100644 --- a/lib/pages/downloaded_page.dart +++ b/lib/pages/downloaded_page.dart @@ -9,6 +9,7 @@ import 'package:pixes/components/page_route.dart'; import 'package:pixes/components/title_bar.dart'; import 'package:pixes/foundation/app.dart'; import 'package:pixes/network/download.dart'; +import 'package:pixes/pages/illust_page.dart'; import 'package:pixes/utils/translation.dart'; import 'package:share_plus/share_plus.dart'; import 'package:window_manager/window_manager.dart'; @@ -54,7 +55,7 @@ class _DownloadedPageState extends State { return GridViewWithFixedItemHeight( itemCount: illusts.length, itemHeight: 152, - maxCrossAxisExtent: 560, + maxCrossAxisExtent: 742, builder: (context, index) { return Card( margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8), @@ -113,14 +114,22 @@ class _DownloadedPageState extends State { child: Text("View".tl).fixWidth(42), onPressed: () { App.rootNavigatorKey.currentState?.push( - AppPageRoute(builder: (context) { - return _DownloadedIllustViewPage( - DownloadManager().getImagePaths( - illusts[index].illustId)); - })); + AppPageRoute(builder: (context) { + return _DownloadedIllustViewPage( + DownloadManager().getImagePaths( + illusts[index].illustId)); + })); }, ), - const SizedBox(width: 8), + const SizedBox(width: 6), + Button( + child: Text("Info".tl).fixWidth(42), + onPressed: () { + context.to(() => IllustPageWithId( + illusts[index].illustId.toString())); + }, + ), + const SizedBox(width: 6), FlyoutTarget( controller: flyoutControllers[index], child: Button( diff --git a/lib/pages/illust_page.dart b/lib/pages/illust_page.dart index fa82b63..6917129 100644 --- a/lib/pages/illust_page.dart +++ b/lib/pages/illust_page.dart @@ -887,3 +887,23 @@ class _CommentsPageState extends MultiPageLoadingState<_CommentsPage, Comment> { } +class IllustPageWithId extends StatefulWidget { + const IllustPageWithId(this.id, {super.key}); + + final String id; + + @override + State createState() => _IllustPageWithIdState(); +} + +class _IllustPageWithIdState extends LoadingState { + @override + Widget buildContent(BuildContext context, Illust data) { + return IllustPage(data); + } + + @override + Future> loadData() { + return Network().getIllustByID(widget.id); + } +} diff --git a/lib/pages/search_page.dart b/lib/pages/search_page.dart index 0c5401e..3ff86cf 100644 --- a/lib/pages/search_page.dart +++ b/lib/pages/search_page.dart @@ -2,10 +2,12 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:pixes/appdata.dart'; import 'package:pixes/components/loading.dart'; +import 'package:pixes/components/message.dart'; import 'package:pixes/components/page_route.dart'; import 'package:pixes/components/user_preview.dart'; import 'package:pixes/foundation/app.dart'; import 'package:pixes/network/network.dart'; +import 'package:pixes/pages/illust_page.dart'; import 'package:pixes/pages/user_info_page.dart'; import 'package:pixes/utils/translation.dart'; @@ -41,17 +43,15 @@ class _SearchPageState extends State { case 0: context.to(() => SearchResultPage(text)); case 1: - // TODO: novel search + showToast(context, message: "Not implemented"); case 2: context.to(() => SearchUserResultPage(text)); case 3: - // TODO: artwork id - throw UnimplementedError(); + context.to(() => IllustPageWithId(text)); case 4: context.to(() => UserInfoPage(text)); case 5: - // TODO: novel id - throw UnimplementedError(); + showToast(context, message: "Not implemented"); } }