opt: 首页推荐卡片

This commit is contained in:
guozhigq
2024-04-24 23:56:07 +08:00
parent e699df52e3
commit 72a8c33a66

View File

@ -1,6 +1,7 @@
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';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/utils/feed_back.dart';
import '../../models/model_rec_video_item.dart'; import '../../models/model_rec_video_item.dart';
import 'overlay_pop.dart'; import 'overlay_pop.dart';
import 'stat/danmu.dart'; import 'stat/danmu.dart';
@ -20,15 +21,11 @@ import 'network_img_layer.dart';
class VideoCardV extends StatelessWidget { class VideoCardV extends StatelessWidget {
final dynamic videoItem; final dynamic videoItem;
final int crossAxisCount; final int crossAxisCount;
// final Function()? longPress;
// final Function()? longPressEnd;
const VideoCardV({ const VideoCardV({
Key? key, Key? key,
required this.videoItem, required this.videoItem,
required this.crossAxisCount, required this.crossAxisCount,
// this.longPress,
// this.longPressEnd,
}) : super(key: key); }) : super(key: key);
bool isStringNumeric(String str) { bool isStringNumeric(String str) {
@ -128,60 +125,56 @@ class VideoCardV extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String heroTag = Utils.makeHeroTag(videoItem.id); String heroTag = Utils.makeHeroTag(videoItem.id);
return Card( return InkWell(
elevation: 0, onTap: () async => onPushDetail(heroTag),
clipBehavior: Clip.hardEdge, onLongPress: () {
margin: EdgeInsets.zero, SmartDialog.show(
child: InkWell( builder: (context) => OverlayPop(
onTap: () async => onPushDetail(heroTag), videoItem: videoItem,
onLongPress: () { closeFn: () => SmartDialog.dismiss(),
SmartDialog.show( ),
builder: (context) => OverlayPop( );
videoItem: videoItem, },
closeFn: () => SmartDialog.dismiss(), borderRadius: BorderRadius.circular(16),
), child: Column(
); children: [
}, AspectRatio(
child: Column( aspectRatio: StyleString.aspectRatio,
children: [ child: LayoutBuilder(builder: (context, boxConstraints) {
AspectRatio( double maxWidth = boxConstraints.maxWidth;
aspectRatio: StyleString.aspectRatio, double maxHeight = boxConstraints.maxHeight;
child: LayoutBuilder(builder: (context, boxConstraints) { return Stack(
double maxWidth = boxConstraints.maxWidth; children: [
double maxHeight = boxConstraints.maxHeight; Hero(
return Stack( tag: heroTag,
children: [ child: NetworkImgLayer(
Hero( src: videoItem.pic,
tag: heroTag, width: maxWidth,
child: NetworkImgLayer( height: maxHeight,
src: videoItem.pic,
width: maxWidth,
height: maxHeight,
),
), ),
if (videoItem.duration > 0) ),
if (crossAxisCount == 1) ...[ if (videoItem.duration > 0)
PBadge( if (crossAxisCount == 1) ...[
bottom: 10, PBadge(
right: 10, bottom: 10,
text: Utils.timeFormat(videoItem.duration), right: 10,
) text: Utils.timeFormat(videoItem.duration),
] else ...[ )
PBadge( ] else ...[
bottom: 6, PBadge(
right: 7, bottom: 6,
size: 'small', right: 7,
type: 'gray', size: 'small',
text: Utils.timeFormat(videoItem.duration), type: 'gray',
) text: Utils.timeFormat(videoItem.duration),
], )
], ],
); ],
}), );
), }),
VideoContent(videoItem: videoItem, crossAxisCount: crossAxisCount) ),
], VideoContent(videoItem: videoItem, crossAxisCount: crossAxisCount)
), ],
), ),
); );
} }
@ -252,11 +245,28 @@ class VideoContent extends StatelessWidget {
const Spacer(), const Spacer(),
], ],
if (videoItem.goto == 'av') if (videoItem.goto == 'av')
VideoPopupMenu( SizedBox(
size: 24, width: 24,
iconSize: 14, height: 24,
videoItem: videoItem, child: IconButton(
), onPressed: () {
feedBack();
showModalBottomSheet(
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (context) {
return MorePanel(videoItem: videoItem);
},
);
},
icon: Icon(
Icons.more_vert_outlined,
color: Theme.of(context).colorScheme.outline,
size: 14,
),
),
)
], ],
), ),
], ],
@ -279,15 +289,9 @@ class VideoStat extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Row( return Row(
children: [ children: [
StatView( StatView(theme: 'gray', view: videoItem.stat.view),
theme: 'gray',
view: videoItem.stat.view,
),
const SizedBox(width: 8), const SizedBox(width: 8),
StatDanMu( StatDanMu(theme: 'gray', danmu: videoItem.stat.danmu),
theme: 'gray',
danmu: videoItem.stat.danmu,
),
if (videoItem is RecVideoItemModel) ...<Widget>[ if (videoItem is RecVideoItemModel) ...<Widget>[
crossAxisCount > 1 ? const Spacer() : const SizedBox(width: 8), crossAxisCount > 1 ? const Spacer() : const SizedBox(width: 8),
RichText( RichText(
@ -306,98 +310,98 @@ class VideoStat extends StatelessWidget {
} }
} }
class VideoPopupMenu extends StatelessWidget { class MorePanel extends StatelessWidget {
final double? size;
final double? iconSize;
final dynamic videoItem; final dynamic videoItem;
const MorePanel({super.key, required this.videoItem});
const VideoPopupMenu({ Future<dynamic> menuActionHandler(String type) async {
Key? key, switch (type) {
required this.size, case 'block':
required this.iconSize, blockUser();
required this.videoItem, break;
}) : super(key: key); case 'watchLater':
var res = await UserHttp.toViewLater(bvid: videoItem.bvid as String);
SmartDialog.showToast(res['msg']);
Get.back();
break;
default:
}
}
void blockUser() async {
SmartDialog.show(
useSystem: true,
animationType: SmartAnimationType.centerFade_otherSlide,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: Text('确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?'
'\n\n被拉黑的Up可以在隐私设置-黑名单管理中解除'),
actions: [
TextButton(
onPressed: () => SmartDialog.dismiss(),
child: Text(
'点错了',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () async {
var res = await VideoHttp.relationMod(
mid: videoItem.owner.mid,
act: 5,
reSrc: 11,
);
SmartDialog.dismiss();
SmartDialog.showToast(res['msg'] ?? '成功');
},
child: const Text('确认'),
)
],
);
},
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return Container(
width: size, padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
height: size, child: Column(
child: PopupMenuButton<String>( mainAxisSize: MainAxisSize.min,
padding: EdgeInsets.zero, children: [
icon: Icon( InkWell(
Icons.more_vert_outlined, onTap: () => Get.back(),
color: Theme.of(context).colorScheme.outline, child: Container(
size: iconSize, height: 35,
), padding: const EdgeInsets.only(bottom: 2),
position: PopupMenuPosition.under, child: Center(
onSelected: (String type) {}, child: Container(
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[ width: 32,
PopupMenuItem<String>( height: 3,
onTap: () async { decoration: BoxDecoration(
var res = color: Theme.of(context).colorScheme.outline,
await UserHttp.toViewLater(bvid: videoItem.bvid as String); borderRadius: const BorderRadius.all(Radius.circular(3))),
SmartDialog.showToast(res['msg']); ),
}, ),
value: 'pause',
height: 40,
child: const Row(
children: [
Icon(Icons.watch_later_outlined, size: 16),
SizedBox(width: 6),
Text('稍后再看', style: TextStyle(fontSize: 13))
],
), ),
), ),
const PopupMenuDivider(), ListTile(
PopupMenuItem<String>( onTap: () async => await menuActionHandler('block'),
onTap: () async { minLeadingWidth: 0,
SmartDialog.show( leading: const Icon(Icons.block, size: 19),
useSystem: true, title: Text(
animationType: SmartAnimationType.centerFade_otherSlide, '拉黑up主 「${videoItem.owner.name}',
builder: (BuildContext context) { style: Theme.of(context).textTheme.titleSmall,
return AlertDialog(
title: const Text('提示'),
content: Text(
'确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?'
'\n\n被拉黑的Up可以在隐私设置-黑名单管理中解除'),
actions: [
TextButton(
onPressed: () => SmartDialog.dismiss(),
child: Text(
'点错了',
style: TextStyle(
color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () async {
var res = await VideoHttp.relationMod(
mid: videoItem.owner.mid,
act: 5,
reSrc: 11,
);
SmartDialog.dismiss();
SmartDialog.showToast(res['msg'] ?? '成功');
},
child: const Text('确认'),
)
],
);
},
);
},
value: 'pause',
height: 40,
child: Row(
children: [
const Icon(Icons.block, size: 16),
const SizedBox(width: 6),
Text('拉黑:${videoItem.owner.name}',
style: const TextStyle(fontSize: 13))
],
), ),
), ),
ListTile(
onTap: () async => await menuActionHandler('watchLater'),
minLeadingWidth: 0,
leading: const Icon(Icons.watch_later_outlined, size: 19),
title:
Text('添加至稍后再看', style: Theme.of(context).textTheme.titleSmall),
),
], ],
), ),
); );