From e3c920dc870f83712f8ba440704f949f606b87ee Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Sat, 7 Jun 2025 15:00:21 +0800 Subject: [PATCH] opt view later Signed-off-by: bggRGjQaUbCoE --- lib/common/widgets/image/image_save.dart | 57 ++++-- .../widgets/video_card/video_card_h.dart | 1 + .../widgets/video_card/video_card_v.dart | 1 + lib/http/user.dart | 12 +- lib/models_new/fav/fav_detail/media.dart | 5 +- lib/pages/dynamics/widgets/dynamic_panel.dart | 8 +- lib/pages/dynamics/widgets/module_panel.dart | 5 +- lib/pages/fav_detail/view.dart | 191 ++++++++++-------- .../fav_detail/widget/fav_video_card.dart | 1 + lib/pages/history/widgets/item.dart | 1 + .../later/widgets/video_card_h_later.dart | 1 + lib/pages/member_coin/widgets/item.dart | 1 + .../widgets/video_card_v_member_home.dart | 19 +- .../widgets/video_card_h_member_video.dart | 1 + .../widget/sub_video_card.dart | 1 + lib/pages/video/medialist/view.dart | 2 + 16 files changed, 182 insertions(+), 125 deletions(-) diff --git a/lib/common/widgets/image/image_save.dart b/lib/common/widgets/image/image_save.dart index 46384298..aec0327b 100644 --- a/lib/common/widgets/image/image_save.dart +++ b/lib/common/widgets/image/image_save.dart @@ -1,6 +1,7 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; +import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/utils/download.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -9,12 +10,31 @@ import 'package:get/get.dart'; void imageSaveDialog({ required String? title, required String? cover, + dynamic aid, + String? bvid, }) { final double imgWidth = Get.mediaQuery.size.shortestSide - 8 * 2; SmartDialog.show( animationType: SmartAnimationType.centerScale_otherSlide, builder: (context) { final theme = Theme.of(context); + late final iconColor = theme.colorScheme.onSurfaceVariant; + + Widget iconBtn({ + String? tooltip, + required IconData icon, + required VoidCallback? onPressed, + }) { + return iconButton( + context: context, + onPressed: onPressed, + iconSize: 20, + icon: icon, + bgColor: Colors.transparent, + iconColor: iconColor, + ); + } + return Container( width: imgWidth, margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), @@ -66,28 +86,36 @@ void imageSaveDialog({ padding: const EdgeInsets.fromLTRB(12, 10, 8, 10), child: Row( children: [ - Expanded( - child: SelectableText( - title ?? '', - style: theme.textTheme.titleSmall, + if (title != null) + Expanded( + child: SelectableText( + title, + style: theme.textTheme.titleSmall, + ), + ) + else + const Spacer(), + if (aid != null || bvid != null) + iconBtn( + tooltip: '稍后再看', + onPressed: () => { + SmartDialog.dismiss(), + UserHttp.toViewLater(aid: aid, bvid: bvid).then( + (res) => SmartDialog.showToast(res['msg']), + ), + }, + icon: Icons.watch_later_outlined, ), - ), if (cover?.isNotEmpty == true) ...[ - const SizedBox(width: 4), - iconButton( - context: context, + iconBtn( tooltip: '分享', onPressed: () { SmartDialog.dismiss(); DownloadUtils.onShareImg(cover!); }, - iconSize: 20, icon: Icons.share, - bgColor: Colors.transparent, - iconColor: theme.colorScheme.onSurfaceVariant, ), - iconButton( - context: context, + iconBtn( tooltip: '保存封面图', onPressed: () async { bool saveStatus = await DownloadUtils.downloadImg( @@ -98,10 +126,7 @@ void imageSaveDialog({ SmartDialog.dismiss(); } }, - iconSize: 20, icon: Icons.download, - bgColor: Colors.transparent, - iconColor: theme.colorScheme.onSurfaceVariant, ), ], ], diff --git a/lib/common/widgets/video_card/video_card_h.dart b/lib/common/widgets/video_card/video_card_h.dart index b3718877..f8d2f553 100644 --- a/lib/common/widgets/video_card/video_card_h.dart +++ b/lib/common/widgets/video_card/video_card_h.dart @@ -59,6 +59,7 @@ class VideoCardH extends StatelessWidget { child: InkWell( onLongPress: onLongPress ?? () => imageSaveDialog( + bvid: videoItem.bvid, title: videoItem.title, cover: videoItem.cover, ), diff --git a/lib/common/widgets/video_card/video_card_v.dart b/lib/common/widgets/video_card/video_card_v.dart index a6bbf9de..1b17e456 100644 --- a/lib/common/widgets/video_card/video_card_v.dart +++ b/lib/common/widgets/video_card/video_card_v.dart @@ -108,6 +108,7 @@ class VideoCardV extends StatelessWidget { onLongPress: () => imageSaveDialog( title: videoItem.title, cover: videoItem.cover, + bvid: videoItem.bvid, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/http/user.dart b/lib/http/user.dart index 3be43e28..861df6ab 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -130,15 +130,13 @@ class UserHttp { // 稍后再看 static Future toViewLater({String? bvid, dynamic aid}) async { - var data = {'csrf': Accounts.main.csrf}; - if (bvid != null) { - data['bvid'] = bvid; - } else if (aid != null) { - data['aid'] = aid; - } var res = await Request().post( Api.toViewLater, - queryParameters: data, + queryParameters: { + if (aid != null) 'aid': aid, + if (bvid != null) 'bvid': bvid, + 'csrf': Accounts.main.csrf, + }, ); if (res.data['code'] == 0) { return {'status': true, 'msg': 'yeah!稍后再看'}; diff --git a/lib/models_new/fav/fav_detail/media.dart b/lib/models_new/fav/fav_detail/media.dart index 4cc1f6ae..573ef82e 100644 --- a/lib/models_new/fav/fav_detail/media.dart +++ b/lib/models_new/fav/fav_detail/media.dart @@ -19,7 +19,6 @@ class FavDetailItemModel with MultiSelectData { int? ctime; int? pubtime; int? favTime; - String? bvId; String? bvid; Ogv? ogv; Ugc? ugc; @@ -40,7 +39,6 @@ class FavDetailItemModel with MultiSelectData { this.ctime, this.pubtime, this.favTime, - this.bvId, this.bvid, this.ogv, this.ugc, @@ -67,8 +65,7 @@ class FavDetailItemModel with MultiSelectData { ctime: json['ctime'] as int?, pubtime: json['pubtime'] as int?, favTime: json['fav_time'] as int?, - bvId: json['bv_id'] as String?, - bvid: json['bvid'] as String?, + bvid: json['bvid'] ?? json['bv_id'], ogv: json['ogv'] == null ? null : Ogv.fromJson(json['ogv']), ugc: json['ugc'] == null ? null diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index 44507c9d..48aa5f83 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -104,17 +104,20 @@ class DynamicPanel extends StatelessWidget { BuildContext context, Function(BuildContext) morePanel, ) { - late String? title; - late String? cover; + String? title; + String? cover; + String? bvid; late final major = item.modules.moduleDynamic?.major; switch (item.type) { case 'DYNAMIC_TYPE_AV': title = major?.archive?.title; cover = major?.archive?.cover; + bvid = major?.archive?.bvid; break; case 'DYNAMIC_TYPE_UGC_SEASON': title = major?.ugcSeason?.title; cover = major?.ugcSeason?.cover; + bvid = major?.ugcSeason?.bvid; break; case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': title = major?.pgc?.title; @@ -135,6 +138,7 @@ class DynamicPanel extends StatelessWidget { imageSaveDialog( title: title, cover: cover, + bvid: bvid, ); } } diff --git a/lib/pages/dynamics/widgets/module_panel.dart b/lib/pages/dynamics/widgets/module_panel.dart index a1e0a304..a92c316e 100644 --- a/lib/pages/dynamics/widgets/module_panel.dart +++ b/lib/pages/dynamics/widgets/module_panel.dart @@ -54,17 +54,19 @@ Widget module( onLongPress: isNoneMajor ? null : () { - late String? title, cover; + String? title, cover, bvid; late var origMajor = orig.modules.moduleDynamic?.major; late var major = item.modules.moduleDynamic?.major; switch (orig.type) { case 'DYNAMIC_TYPE_AV': title = origMajor?.archive?.title; cover = origMajor?.archive?.cover; + bvid = origMajor?.archive?.bvid; break; case 'DYNAMIC_TYPE_UGC_SEASON': title = origMajor?.ugcSeason?.title; cover = origMajor?.ugcSeason?.cover; + bvid = origMajor?.ugcSeason?.bvid; break; case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': title = origMajor?.pgc?.title; @@ -84,6 +86,7 @@ Widget module( imageSaveDialog( title: title, cover: cover, + bvid: bvid, ); }, child: Container( diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 03da756c..bf48866c 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -90,16 +90,24 @@ class _FavDetailPageState extends State { Widget _buildHeader(ThemeData theme) { return SliverAppBar.medium( leading: _favDetailController.enableMultiSelect.value - ? IconButton( - tooltip: '取消', - onPressed: _favDetailController.handleSelect, - icon: const Icon(Icons.close_outlined), + ? Row( + children: [ + IconButton( + tooltip: '取消', + onPressed: _favDetailController.handleSelect, + icon: const Icon(Icons.close_outlined), + ), + Text( + '已选: ${_favDetailController.checkedCount.value}', + style: const TextStyle(fontSize: 15), + ), + ], ) : null, expandedHeight: kToolbarHeight + 130, pinned: true, title: _favDetailController.enableMultiSelect.value - ? Text('已选: ${_favDetailController.checkedCount.value}') + ? null : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -288,7 +296,6 @@ class _FavDetailPageState extends State { fontSize: 12.5, color: theme.colorScheme.outline, ); - final item = _favDetailController.item.value; return FlexibleSpaceBar( background: Padding( padding: EdgeInsets.only( @@ -300,97 +307,103 @@ class _FavDetailPageState extends State { child: SizedBox( height: 110, child: Obx( - () => Row( - spacing: 12, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - Hero( - tag: _favDetailController.heroTag, - child: NetworkImgLayer( - width: 176, - height: 110, - src: item.cover, - ), - ), - Positioned( - right: 6, - top: 6, - child: Obx(() { - if (_favDetailController.isOwner.value != false) { - return const SizedBox.shrink(); - } - bool isFav = - _favDetailController.item.value.favState == 1; - return iconButton( - context: context, - size: 28, - iconSize: 18, - tooltip: '${isFav ? '取消' : ''}收藏', - onPressed: () => _favDetailController.onFav(isFav), - icon: isFav ? Icons.favorite : Icons.favorite_border, - bgColor: - isFav ? null : theme.colorScheme.onInverseSurface, - iconColor: - isFav ? null : theme.colorScheme.onSurfaceVariant, - ); - }), - ) - ], - ), - if (item.title != null) - Expanded( - child: Column( - spacing: 4, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.title!, - style: TextStyle( - fontSize: theme.textTheme.titleMedium!.fontSize, - fontWeight: FontWeight.bold, - ), + () { + final item = _favDetailController.item.value; + return Row( + spacing: 12, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + Hero( + tag: _favDetailController.heroTag, + child: NetworkImgLayer( + width: 176, + height: 110, + src: item.cover, ), - GestureDetector( - onTap: () => - Get.toNamed('/member?mid=${item.upper!.mid}'), - child: Text( - item.upper!.name!, + ), + Positioned( + right: 6, + top: 6, + child: Obx(() { + if (_favDetailController.isOwner.value != false) { + return const SizedBox.shrink(); + } + bool isFav = + _favDetailController.item.value.favState == 1; + return iconButton( + context: context, + size: 28, + iconSize: 18, + tooltip: '${isFav ? '取消' : ''}收藏', + onPressed: () => _favDetailController.onFav(isFav), + icon: + isFav ? Icons.favorite : Icons.favorite_border, + bgColor: isFav + ? null + : theme.colorScheme.onInverseSurface, + iconColor: isFav + ? null + : theme.colorScheme.onSurfaceVariant, + ); + }), + ) + ], + ), + if (item.title != null) + Expanded( + child: Column( + spacing: 4, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.title!, style: TextStyle( - color: theme.colorScheme.primary, + fontSize: theme.textTheme.titleMedium!.fontSize, + fontWeight: FontWeight.bold, ), ), - ), - if (item.intro?.isNotEmpty == true) - Text( - item.intro!, - style: style, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - if (item.attr != null) ...[ - Expanded( - child: Align( - alignment: Alignment.bottomLeft, - child: Text( - '共${item.mediaCount}条视频 · ${Utils.isPublicFavText(item.attr)}', - textAlign: TextAlign.end, - style: style, + GestureDetector( + onTap: () => + Get.toNamed('/member?mid=${item.upper!.mid}'), + child: Text( + item.upper!.name!, + style: TextStyle( + color: theme.colorScheme.primary, ), ), ), + if (item.intro?.isNotEmpty == true) + Text( + item.intro!, + style: style, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + if (item.attr != null) ...[ + Expanded( + child: Align( + alignment: Alignment.bottomLeft, + child: Text( + '共${item.mediaCount}条视频 · ${Utils.isPublicFavText(item.attr)}', + textAlign: TextAlign.end, + style: style, + ), + ), + ), + ], ], - ], - ), - ) - else - SizedBox.shrink( - key: ValueKey(_favDetailController.item.value), - ) - ], - ), + ), + ) + else + SizedBox.shrink( + key: ValueKey(_favDetailController.item.value), + ) + ], + ); + }, ), ), ), diff --git a/lib/pages/fav_detail/widget/fav_video_card.dart b/lib/pages/fav_detail/widget/fav_video_card.dart index 068a1876..b56d4fe1 100644 --- a/lib/pages/fav_detail/widget/fav_video_card.dart +++ b/lib/pages/fav_detail/widget/fav_video_card.dart @@ -60,6 +60,7 @@ class FavVideoCardH extends StatelessWidget { () => imageSaveDialog( title: item.title, cover: item.cover, + bvid: item.bvid, ), child: Padding( padding: const EdgeInsets.symmetric( diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index 14aeb0ff..fe01fdb1 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -93,6 +93,7 @@ class HistoryItem extends StatelessWidget { imageSaveDialog( title: item.title, cover: item.cover, + bvid: bvid, ); }, child: Stack( diff --git a/lib/pages/later/widgets/video_card_h_later.dart b/lib/pages/later/widgets/video_card_h_later.dart index ead8a957..0865617f 100644 --- a/lib/pages/later/widgets/video_card_h_later.dart +++ b/lib/pages/later/widgets/video_card_h_later.dart @@ -44,6 +44,7 @@ class VideoCardHLater extends StatelessWidget { () => imageSaveDialog( title: videoItem.title, cover: videoItem.pic, + bvid: videoItem.bvid, ), onTap: onTap ?? () async { diff --git a/lib/pages/member_coin/widgets/item.dart b/lib/pages/member_coin/widgets/item.dart index 161cb818..92833fb8 100644 --- a/lib/pages/member_coin/widgets/item.dart +++ b/lib/pages/member_coin/widgets/item.dart @@ -50,6 +50,7 @@ class MemberCoinLikeItem extends StatelessWidget { onLongPress: () => imageSaveDialog( title: item.title, cover: item.cover, + aid: item.param, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/member_home/widgets/video_card_v_member_home.dart b/lib/pages/member_home/widgets/video_card_v_member_home.dart index 8a16d6af..24ec19f7 100644 --- a/lib/pages/member_home/widgets/video_card_v_member_home.dart +++ b/lib/pages/member_home/widgets/video_card_v_member_home.dart @@ -26,27 +26,32 @@ class VideoCardVMemberHome extends StatelessWidget { case 'bangumi': PageUtils.viewPgc(epId: videoItem.param); break; + case 'av': - if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) { - if (PageUtils.viewPgcFromUri(videoItem.uri!)) { - return; + if (videoItem.isPgc == true) { + if (videoItem.uri?.isNotEmpty == true) { + PageUtils.viewPgcFromUri(videoItem.uri!); } + return; } + String? aid = videoItem.param; String? bvid = videoItem.bvid; if (aid == null && bvid == null) { return; } - int? cid = videoItem.cid; - cid ??= await SearchHttp.ab2c(aid: aid, bvid: bvid); + + bvid ??= IdUtils.av2bv(int.parse(aid!)); + int? cid = videoItem.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); PageUtils.toVideoPage( - 'bvid=${bvid ?? IdUtils.av2bv(int.parse(aid!))}&cid=$cid', + 'bvid=$bvid&cid=$cid', arguments: { 'pic': videoItem.cover, 'heroTag': heroTag, }, ); break; + default: if (videoItem.uri?.isNotEmpty == true) { PiliScheme.routePushFromUrl(videoItem.uri!); @@ -64,6 +69,8 @@ class VideoCardVMemberHome extends StatelessWidget { onLongPress: () => imageSaveDialog( title: videoItem.title, cover: videoItem.cover, + aid: videoItem.param, + bvid: videoItem.bvid, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/member_video/widgets/video_card_h_member_video.dart b/lib/pages/member_video/widgets/video_card_h_member_video.dart index 62aa0c7c..ab19ef6e 100644 --- a/lib/pages/member_video/widgets/video_card_h_member_video.dart +++ b/lib/pages/member_video/widgets/video_card_h_member_video.dart @@ -37,6 +37,7 @@ class VideoCardHMemberVideo extends StatelessWidget { onLongPress: () => imageSaveDialog( title: videoItem.title, cover: videoItem.cover, + bvid: videoItem.bvid, ), onTap: onTap ?? () async { diff --git a/lib/pages/subscription_detail/widget/sub_video_card.dart b/lib/pages/subscription_detail/widget/sub_video_card.dart index 1a4e7d27..af2dafb7 100644 --- a/lib/pages/subscription_detail/widget/sub_video_card.dart +++ b/lib/pages/subscription_detail/widget/sub_video_card.dart @@ -42,6 +42,7 @@ class SubVideoCardH extends StatelessWidget { onLongPress: () => imageSaveDialog( title: videoItem.title, cover: videoItem.cover, + bvid: videoItem.bvid, ), child: Padding( padding: const EdgeInsets.symmetric( diff --git a/lib/pages/video/medialist/view.dart b/lib/pages/video/medialist/view.dart index d6b91662..123dc7ed 100644 --- a/lib/pages/video/medialist/view.dart +++ b/lib/pages/video/medialist/view.dart @@ -174,6 +174,8 @@ class _MediaListPanelState onLongPress: () => imageSaveDialog( title: item.title, cover: item.cover, + aid: item.aid, + bvid: item.bvid, ), child: Stack( clipBehavior: Clip.none,