import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart'; import 'package:PiliPlus/common/widgets/video_popup_menu.dart'; import 'package:PiliPlus/http/search.dart'; import 'package:PiliPlus/models/common/badge_type.dart'; import 'package:PiliPlus/models/common/stat_type.dart'; import 'package:PiliPlus/models/model_rec_video_item.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/date_util.dart'; import 'package:PiliPlus/utils/duration_util.dart'; import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:intl/intl.dart'; // 视频卡片 - 垂直布局 class VideoCardV extends StatelessWidget { final BaseRecVideoItemModel videoItem; final VoidCallback? onRemove; const VideoCardV({ super.key, required this.videoItem, this.onRemove, }); Future onPushDetail(String heroTag) async { String? goto = videoItem.goto; switch (goto) { case 'bangumi': PageUtils.viewPgc(epId: videoItem.param!); break; case 'av': String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid!); int? cid = videoItem.cid ?? await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid); if (cid != null) { PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'heroTag': heroTag, 'videoItem': videoItem, }, ); } break; // 动态 case 'picture': try { PiliScheme.routePushFromUrl(videoItem.uri!); } catch (err) { SmartDialog.showToast(err.toString()); } break; default: if (videoItem.uri?.isNotEmpty == true) { PiliScheme.routePushFromUrl(videoItem.uri!); } } } @override Widget build(BuildContext context) { return Stack( clipBehavior: Clip.none, children: [ Card( clipBehavior: Clip.hardEdge, child: InkWell( onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.aid)), onLongPress: () => imageSaveDialog( title: videoItem.title, cover: videoItem.cover, bvid: videoItem.bvid, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ AspectRatio( aspectRatio: StyleString.aspectRatio, child: LayoutBuilder( builder: (context, boxConstraints) { double maxWidth = boxConstraints.maxWidth; double maxHeight = boxConstraints.maxHeight; return Stack( clipBehavior: Clip.none, children: [ NetworkImgLayer( src: videoItem.cover, width: maxWidth, height: maxHeight, radius: 0, ), if (videoItem.duration > 0) PBadge( bottom: 6, right: 7, size: PBadgeSize.small, type: PBadgeType.gray, text: DurationUtil.formatDuration( videoItem.duration, ), ), ], ); }, ), ), content(context), ], ), ), ), if (videoItem.goto == 'av') Positioned( right: -5, bottom: -2, child: VideoPopupMenu( size: 29, iconSize: 17, videoItem: videoItem, onRemove: onRemove, ), ), ], ); } Widget content(BuildContext context) { final theme = Theme.of(context); return Expanded( child: Padding( padding: const EdgeInsets.fromLTRB(6, 5, 6, 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Text( "${videoItem.title}\n", maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( height: 1.38, ), ), ), videoStat(context, theme), Row( spacing: 2, children: [ if (videoItem.goto == 'bangumi') PBadge( text: videoItem.pgcBadge, isStack: false, size: PBadgeSize.small, type: PBadgeType.line_primary, fontSize: 9, ), if (videoItem.rcmdReason != null) PBadge( text: videoItem.rcmdReason, isStack: false, size: PBadgeSize.small, type: PBadgeType.secondary, ), if (videoItem.goto == 'picture') const PBadge( text: '动态', isStack: false, size: PBadgeSize.small, type: PBadgeType.line_primary, fontSize: 9, ), if (videoItem.isFollowed) const PBadge( text: '已关注', isStack: false, size: PBadgeSize.small, type: PBadgeType.secondary, ), Expanded( flex: 1, child: Text( videoItem.owner.name.toString(), maxLines: 1, overflow: TextOverflow.clip, style: TextStyle( height: 1.5, fontSize: theme.textTheme.labelMedium!.fontSize, color: theme.colorScheme.outline, ), ), ), if (videoItem.goto == 'av') const SizedBox(width: 10), ], ), ], ), ), ); } static final shortFormat = DateFormat('M-d'); static final longFormat = DateFormat('yy-M-d'); Widget videoStat(BuildContext context, ThemeData theme) { return Row( children: [ StatWidget( type: StatType.play, value: videoItem.stat.view, ), if (videoItem.goto != 'picture') ...[ const SizedBox(width: 4), StatWidget( type: StatType.danmaku, value: videoItem.stat.danmu, ), ], if (videoItem is RecVideoItemModel) ...[ const Spacer(), Text.rich( maxLines: 1, TextSpan( style: TextStyle( fontSize: theme.textTheme.labelSmall!.fontSize, color: theme.colorScheme.outline.withValues(alpha: 0.8), ), text: DateUtil.dateFormat( videoItem.pubdate, shortFormat: shortFormat, longFormat: longFormat, ), ), ), const SizedBox(width: 2), ], // deprecated // else if (videoItem is RecVideoItemAppModel && // videoItem.desc != null && // videoItem.desc!.contains(' · ')) ...[ // const Spacer(), // Text.rich( // maxLines: 1, // TextSpan( // style: TextStyle( // fontSize: theme.textTheme.labelSmall!.fontSize, // color: theme.colorScheme.outline.withValues(alpha: 0.8), // ), // text: Utils.shortenChineseDateString( // videoItem.desc!.split(' · ').last)), // ), // const SizedBox(width: 2), // ] ], ); } }