opt view later

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-06-07 15:00:21 +08:00
parent 13f1392821
commit e3c920dc87
16 changed files with 182 additions and 125 deletions

View File

@@ -1,6 +1,7 @@
import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.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:PiliPlus/utils/download.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -9,12 +10,31 @@ import 'package:get/get.dart';
void imageSaveDialog({ void imageSaveDialog({
required String? title, required String? title,
required String? cover, required String? cover,
dynamic aid,
String? bvid,
}) { }) {
final double imgWidth = Get.mediaQuery.size.shortestSide - 8 * 2; final double imgWidth = Get.mediaQuery.size.shortestSide - 8 * 2;
SmartDialog.show( SmartDialog.show(
animationType: SmartAnimationType.centerScale_otherSlide, animationType: SmartAnimationType.centerScale_otherSlide,
builder: (context) { builder: (context) {
final theme = Theme.of(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( return Container(
width: imgWidth, width: imgWidth,
margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
@@ -66,28 +86,36 @@ void imageSaveDialog({
padding: const EdgeInsets.fromLTRB(12, 10, 8, 10), padding: const EdgeInsets.fromLTRB(12, 10, 8, 10),
child: Row( child: Row(
children: [ children: [
if (title != null)
Expanded( Expanded(
child: SelectableText( child: SelectableText(
title ?? '', title,
style: theme.textTheme.titleSmall, 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) ...[ if (cover?.isNotEmpty == true) ...[
const SizedBox(width: 4), iconBtn(
iconButton(
context: context,
tooltip: '分享', tooltip: '分享',
onPressed: () { onPressed: () {
SmartDialog.dismiss(); SmartDialog.dismiss();
DownloadUtils.onShareImg(cover!); DownloadUtils.onShareImg(cover!);
}, },
iconSize: 20,
icon: Icons.share, icon: Icons.share,
bgColor: Colors.transparent,
iconColor: theme.colorScheme.onSurfaceVariant,
), ),
iconButton( iconBtn(
context: context,
tooltip: '保存封面图', tooltip: '保存封面图',
onPressed: () async { onPressed: () async {
bool saveStatus = await DownloadUtils.downloadImg( bool saveStatus = await DownloadUtils.downloadImg(
@@ -98,10 +126,7 @@ void imageSaveDialog({
SmartDialog.dismiss(); SmartDialog.dismiss();
} }
}, },
iconSize: 20,
icon: Icons.download, icon: Icons.download,
bgColor: Colors.transparent,
iconColor: theme.colorScheme.onSurfaceVariant,
), ),
], ],
], ],

View File

@@ -59,6 +59,7 @@ class VideoCardH extends StatelessWidget {
child: InkWell( child: InkWell(
onLongPress: onLongPress ?? onLongPress: onLongPress ??
() => imageSaveDialog( () => imageSaveDialog(
bvid: videoItem.bvid,
title: videoItem.title, title: videoItem.title,
cover: videoItem.cover, cover: videoItem.cover,
), ),

View File

@@ -108,6 +108,7 @@ class VideoCardV extends StatelessWidget {
onLongPress: () => imageSaveDialog( onLongPress: () => imageSaveDialog(
title: videoItem.title, title: videoItem.title,
cover: videoItem.cover, cover: videoItem.cover,
bvid: videoItem.bvid,
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -130,15 +130,13 @@ class UserHttp {
// 稍后再看 // 稍后再看
static Future toViewLater({String? bvid, dynamic aid}) async { 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( var res = await Request().post(
Api.toViewLater, Api.toViewLater,
queryParameters: data, queryParameters: {
if (aid != null) 'aid': aid,
if (bvid != null) 'bvid': bvid,
'csrf': Accounts.main.csrf,
},
); );
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return {'status': true, 'msg': 'yeah稍后再看'}; return {'status': true, 'msg': 'yeah稍后再看'};

View File

@@ -19,7 +19,6 @@ class FavDetailItemModel with MultiSelectData {
int? ctime; int? ctime;
int? pubtime; int? pubtime;
int? favTime; int? favTime;
String? bvId;
String? bvid; String? bvid;
Ogv? ogv; Ogv? ogv;
Ugc? ugc; Ugc? ugc;
@@ -40,7 +39,6 @@ class FavDetailItemModel with MultiSelectData {
this.ctime, this.ctime,
this.pubtime, this.pubtime,
this.favTime, this.favTime,
this.bvId,
this.bvid, this.bvid,
this.ogv, this.ogv,
this.ugc, this.ugc,
@@ -67,8 +65,7 @@ class FavDetailItemModel with MultiSelectData {
ctime: json['ctime'] as int?, ctime: json['ctime'] as int?,
pubtime: json['pubtime'] as int?, pubtime: json['pubtime'] as int?,
favTime: json['fav_time'] as int?, favTime: json['fav_time'] as int?,
bvId: json['bv_id'] as String?, bvid: json['bvid'] ?? json['bv_id'],
bvid: json['bvid'] as String?,
ogv: json['ogv'] == null ? null : Ogv.fromJson(json['ogv']), ogv: json['ogv'] == null ? null : Ogv.fromJson(json['ogv']),
ugc: json['ugc'] == null ugc: json['ugc'] == null
? null ? null

View File

@@ -104,17 +104,20 @@ class DynamicPanel extends StatelessWidget {
BuildContext context, BuildContext context,
Function(BuildContext) morePanel, Function(BuildContext) morePanel,
) { ) {
late String? title; String? title;
late String? cover; String? cover;
String? bvid;
late final major = item.modules.moduleDynamic?.major; late final major = item.modules.moduleDynamic?.major;
switch (item.type) { switch (item.type) {
case 'DYNAMIC_TYPE_AV': case 'DYNAMIC_TYPE_AV':
title = major?.archive?.title; title = major?.archive?.title;
cover = major?.archive?.cover; cover = major?.archive?.cover;
bvid = major?.archive?.bvid;
break; break;
case 'DYNAMIC_TYPE_UGC_SEASON': case 'DYNAMIC_TYPE_UGC_SEASON':
title = major?.ugcSeason?.title; title = major?.ugcSeason?.title;
cover = major?.ugcSeason?.cover; cover = major?.ugcSeason?.cover;
bvid = major?.ugcSeason?.bvid;
break; break;
case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION':
title = major?.pgc?.title; title = major?.pgc?.title;
@@ -135,6 +138,7 @@ class DynamicPanel extends StatelessWidget {
imageSaveDialog( imageSaveDialog(
title: title, title: title,
cover: cover, cover: cover,
bvid: bvid,
); );
} }
} }

View File

@@ -54,17 +54,19 @@ Widget module(
onLongPress: isNoneMajor onLongPress: isNoneMajor
? null ? null
: () { : () {
late String? title, cover; String? title, cover, bvid;
late var origMajor = orig.modules.moduleDynamic?.major; late var origMajor = orig.modules.moduleDynamic?.major;
late var major = item.modules.moduleDynamic?.major; late var major = item.modules.moduleDynamic?.major;
switch (orig.type) { switch (orig.type) {
case 'DYNAMIC_TYPE_AV': case 'DYNAMIC_TYPE_AV':
title = origMajor?.archive?.title; title = origMajor?.archive?.title;
cover = origMajor?.archive?.cover; cover = origMajor?.archive?.cover;
bvid = origMajor?.archive?.bvid;
break; break;
case 'DYNAMIC_TYPE_UGC_SEASON': case 'DYNAMIC_TYPE_UGC_SEASON':
title = origMajor?.ugcSeason?.title; title = origMajor?.ugcSeason?.title;
cover = origMajor?.ugcSeason?.cover; cover = origMajor?.ugcSeason?.cover;
bvid = origMajor?.ugcSeason?.bvid;
break; break;
case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION':
title = origMajor?.pgc?.title; title = origMajor?.pgc?.title;
@@ -84,6 +86,7 @@ Widget module(
imageSaveDialog( imageSaveDialog(
title: title, title: title,
cover: cover, cover: cover,
bvid: bvid,
); );
}, },
child: Container( child: Container(

View File

@@ -90,16 +90,24 @@ class _FavDetailPageState extends State<FavDetailPage> {
Widget _buildHeader(ThemeData theme) { Widget _buildHeader(ThemeData theme) {
return SliverAppBar.medium( return SliverAppBar.medium(
leading: _favDetailController.enableMultiSelect.value leading: _favDetailController.enableMultiSelect.value
? IconButton( ? Row(
children: [
IconButton(
tooltip: '取消', tooltip: '取消',
onPressed: _favDetailController.handleSelect, onPressed: _favDetailController.handleSelect,
icon: const Icon(Icons.close_outlined), icon: const Icon(Icons.close_outlined),
),
Text(
'已选: ${_favDetailController.checkedCount.value}',
style: const TextStyle(fontSize: 15),
),
],
) )
: null, : null,
expandedHeight: kToolbarHeight + 130, expandedHeight: kToolbarHeight + 130,
pinned: true, pinned: true,
title: _favDetailController.enableMultiSelect.value title: _favDetailController.enableMultiSelect.value
? Text('已选: ${_favDetailController.checkedCount.value}') ? null
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -288,7 +296,6 @@ class _FavDetailPageState extends State<FavDetailPage> {
fontSize: 12.5, fontSize: 12.5,
color: theme.colorScheme.outline, color: theme.colorScheme.outline,
); );
final item = _favDetailController.item.value;
return FlexibleSpaceBar( return FlexibleSpaceBar(
background: Padding( background: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
@@ -300,7 +307,9 @@ class _FavDetailPageState extends State<FavDetailPage> {
child: SizedBox( child: SizedBox(
height: 110, height: 110,
child: Obx( child: Obx(
() => Row( () {
final item = _favDetailController.item.value;
return Row(
spacing: 12, spacing: 12,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -330,11 +339,14 @@ class _FavDetailPageState extends State<FavDetailPage> {
iconSize: 18, iconSize: 18,
tooltip: '${isFav ? '取消' : ''}收藏', tooltip: '${isFav ? '取消' : ''}收藏',
onPressed: () => _favDetailController.onFav(isFav), onPressed: () => _favDetailController.onFav(isFav),
icon: isFav ? Icons.favorite : Icons.favorite_border, icon:
bgColor: isFav ? Icons.favorite : Icons.favorite_border,
isFav ? null : theme.colorScheme.onInverseSurface, bgColor: isFav
iconColor: ? null
isFav ? null : theme.colorScheme.onSurfaceVariant, : theme.colorScheme.onInverseSurface,
iconColor: isFav
? null
: theme.colorScheme.onSurfaceVariant,
); );
}), }),
) )
@@ -390,7 +402,8 @@ class _FavDetailPageState extends State<FavDetailPage> {
key: ValueKey(_favDetailController.item.value), key: ValueKey(_favDetailController.item.value),
) )
], ],
), );
},
), ),
), ),
), ),

View File

@@ -60,6 +60,7 @@ class FavVideoCardH extends StatelessWidget {
() => imageSaveDialog( () => imageSaveDialog(
title: item.title, title: item.title,
cover: item.cover, cover: item.cover,
bvid: item.bvid,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(

View File

@@ -93,6 +93,7 @@ class HistoryItem extends StatelessWidget {
imageSaveDialog( imageSaveDialog(
title: item.title, title: item.title,
cover: item.cover, cover: item.cover,
bvid: bvid,
); );
}, },
child: Stack( child: Stack(

View File

@@ -44,6 +44,7 @@ class VideoCardHLater extends StatelessWidget {
() => imageSaveDialog( () => imageSaveDialog(
title: videoItem.title, title: videoItem.title,
cover: videoItem.pic, cover: videoItem.pic,
bvid: videoItem.bvid,
), ),
onTap: onTap ?? onTap: onTap ??
() async { () async {

View File

@@ -50,6 +50,7 @@ class MemberCoinLikeItem extends StatelessWidget {
onLongPress: () => imageSaveDialog( onLongPress: () => imageSaveDialog(
title: item.title, title: item.title,
cover: item.cover, cover: item.cover,
aid: item.param,
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -26,27 +26,32 @@ class VideoCardVMemberHome extends StatelessWidget {
case 'bangumi': case 'bangumi':
PageUtils.viewPgc(epId: videoItem.param); PageUtils.viewPgc(epId: videoItem.param);
break; break;
case 'av': case 'av':
if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) { if (videoItem.isPgc == true) {
if (PageUtils.viewPgcFromUri(videoItem.uri!)) { if (videoItem.uri?.isNotEmpty == true) {
PageUtils.viewPgcFromUri(videoItem.uri!);
}
return; return;
} }
}
String? aid = videoItem.param; String? aid = videoItem.param;
String? bvid = videoItem.bvid; String? bvid = videoItem.bvid;
if (aid == null && bvid == null) { if (aid == null && bvid == null) {
return; 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( PageUtils.toVideoPage(
'bvid=${bvid ?? IdUtils.av2bv(int.parse(aid!))}&cid=$cid', 'bvid=$bvid&cid=$cid',
arguments: { arguments: {
'pic': videoItem.cover, 'pic': videoItem.cover,
'heroTag': heroTag, 'heroTag': heroTag,
}, },
); );
break; break;
default: default:
if (videoItem.uri?.isNotEmpty == true) { if (videoItem.uri?.isNotEmpty == true) {
PiliScheme.routePushFromUrl(videoItem.uri!); PiliScheme.routePushFromUrl(videoItem.uri!);
@@ -64,6 +69,8 @@ class VideoCardVMemberHome extends StatelessWidget {
onLongPress: () => imageSaveDialog( onLongPress: () => imageSaveDialog(
title: videoItem.title, title: videoItem.title,
cover: videoItem.cover, cover: videoItem.cover,
aid: videoItem.param,
bvid: videoItem.bvid,
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -37,6 +37,7 @@ class VideoCardHMemberVideo extends StatelessWidget {
onLongPress: () => imageSaveDialog( onLongPress: () => imageSaveDialog(
title: videoItem.title, title: videoItem.title,
cover: videoItem.cover, cover: videoItem.cover,
bvid: videoItem.bvid,
), ),
onTap: onTap ?? onTap: onTap ??
() async { () async {

View File

@@ -42,6 +42,7 @@ class SubVideoCardH extends StatelessWidget {
onLongPress: () => imageSaveDialog( onLongPress: () => imageSaveDialog(
title: videoItem.title, title: videoItem.title,
cover: videoItem.cover, cover: videoItem.cover,
bvid: videoItem.bvid,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(

View File

@@ -174,6 +174,8 @@ class _MediaListPanelState
onLongPress: () => imageSaveDialog( onLongPress: () => imageSaveDialog(
title: item.title, title: item.title,
cover: item.cover, cover: item.cover,
aid: item.aid,
bvid: item.bvid,
), ),
child: Stack( child: Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,