Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-01-21 14:26:29 +08:00
parent 0b1f6c4d0e
commit 7a65b777c9
21 changed files with 486 additions and 507 deletions

View File

@@ -24,7 +24,6 @@ class _VideoCustomAction {
}
class VideoPopupMenu extends StatelessWidget {
final double? size;
final double? iconSize;
final double menuItemHeight;
final BaseSimpleVideoItemModel videoItem;
@@ -32,7 +31,6 @@ class VideoPopupMenu extends StatelessWidget {
const VideoPopupMenu({
super.key,
required this.size,
required this.iconSize,
required this.videoItem,
this.onRemove,
@@ -41,358 +39,349 @@ class VideoPopupMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ExcludeSemantics(
child: SizedBox(
width: size,
height: size,
child: PopupMenuButton(
padding: EdgeInsets.zero,
icon: Icon(
Icons.more_vert_outlined,
color: Theme.of(context).colorScheme.outline,
size: iconSize,
),
position: PopupMenuPosition.under,
itemBuilder: (context) =>
[
if (videoItem.bvid?.isNotEmpty == true) ...[
_VideoCustomAction(
videoItem.bvid!,
const Stack(
clipBehavior: Clip.none,
children: [
Icon(MdiIcons.identifier, size: 16),
Icon(MdiIcons.circleOutline, size: 16),
],
),
() => Utils.copyText(videoItem.bvid!),
),
_VideoCustomAction(
'稍后再看',
const Icon(MdiIcons.clockTimeEightOutline, size: 16),
() => UserHttp.toViewLater(bvid: videoItem.bvid),
),
if (videoItem.cid != null && Pref.enableAi)
_VideoCustomAction(
'AI总结',
const Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Icon(Icons.circle_outlined, size: 16),
ExcludeSemantics(
child: Text(
'AI',
style: TextStyle(
fontSize: 10,
height: 1,
fontWeight: FontWeight.w700,
),
strutStyle: StrutStyle(
fontSize: 10,
height: 1,
leading: 0,
fontWeight: FontWeight.w700,
),
textScaler: TextScaler.noScaling,
),
return PopupMenuButton(
padding: EdgeInsets.zero,
icon: Icon(
Icons.more_vert_outlined,
color: Theme.of(context).colorScheme.outline,
size: iconSize,
),
position: PopupMenuPosition.under,
itemBuilder: (context) =>
[
if (videoItem.bvid?.isNotEmpty == true) ...[
_VideoCustomAction(
videoItem.bvid!,
const Stack(
clipBehavior: Clip.none,
children: [
Icon(MdiIcons.identifier, size: 16),
Icon(MdiIcons.circleOutline, size: 16),
],
),
() => Utils.copyText(videoItem.bvid!),
),
_VideoCustomAction(
'稍后再看',
const Icon(MdiIcons.clockTimeEightOutline, size: 16),
() => UserHttp.toViewLater(bvid: videoItem.bvid),
),
if (videoItem.cid != null && Pref.enableAi)
_VideoCustomAction(
'AI总结',
const Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
Icon(Icons.circle_outlined, size: 16),
ExcludeSemantics(
child: Text(
'AI',
style: TextStyle(
fontSize: 10,
height: 1,
fontWeight: FontWeight.w700,
),
],
strutStyle: StrutStyle(
fontSize: 10,
height: 1,
leading: 0,
fontWeight: FontWeight.w700,
),
textScaler: TextScaler.noScaling,
),
),
() async {
final res =
await UgcIntroController.getAiConclusion(
videoItem.bvid!,
videoItem.cid!,
videoItem.owner.mid,
);
if (res != null && context.mounted) {
showDialog(
context: context,
builder: (context) {
return Dialog(
child: Padding(
padding: const .symmetric(vertical: 14),
child: AiConclusionPanel.buildContent(
context,
Theme.of(context),
res,
tap: false,
),
),
);
},
);
}
},
),
],
if (videoItem is! SpaceArchiveItem) ...[
_VideoCustomAction(
'访问:${videoItem.owner.name}',
const Icon(MdiIcons.accountCircleOutline, size: 16),
() => Get.toNamed('/member?mid=${videoItem.owner.mid}'),
],
),
_VideoCustomAction(
'不感兴趣',
const Icon(MdiIcons.thumbDownOutline, size: 16),
() {
String? accessKey = Accounts.get(
AccountType.recommend,
).accessKey;
if (accessKey == null || accessKey == "") {
SmartDialog.showToast("请退出账号后重新登录");
return;
}
if (videoItem case final RecVideoItemAppModel item) {
ThreePoint? tp = item.threePoint;
if (tp == null) {
SmartDialog.showToast("未能获取threePoint");
return;
}
if (tp.dislikeReasons == null &&
tp.feedbacks == null) {
SmartDialog.showToast(
"未能获取dislikeReasons或feedbacks",
() async {
final res = await UgcIntroController.getAiConclusion(
videoItem.bvid!,
videoItem.cid!,
videoItem.owner.mid,
);
if (res != null && context.mounted) {
showDialog(
context: context,
builder: (context) {
return Dialog(
child: Padding(
padding: const .symmetric(vertical: 14),
child: AiConclusionPanel.buildContent(
context,
Theme.of(context),
res,
tap: false,
),
),
);
return;
}
Widget actionButton(Reason? r, Reason? f) {
return SearchText(
text: r?.name ?? f?.name ?? '未知',
onTap: (_) async {
Get.back();
SmartDialog.showLoading(msg: '正在提交');
final res = await VideoHttp.feedDislike(
reasonId: r?.id,
feedbackId: f?.id,
id: item.param!,
goto: item.goto!,
);
SmartDialog.dismiss();
if (res.isSuccess) {
SmartDialog.showToast(
r?.toast ?? f!.toast!,
);
onRemove?.call();
} else {
res.toast();
}
},
},
);
}
},
),
],
if (videoItem is! SpaceArchiveItem) ...[
_VideoCustomAction(
'访问:${videoItem.owner.name}',
const Icon(MdiIcons.accountCircleOutline, size: 16),
() => Get.toNamed('/member?mid=${videoItem.owner.mid}'),
),
_VideoCustomAction(
'不感兴趣',
const Icon(MdiIcons.thumbDownOutline, size: 16),
() {
String? accessKey = Accounts.get(
AccountType.recommend,
).accessKey;
if (accessKey == null || accessKey == "") {
SmartDialog.showToast("请退出账号后重新登录");
return;
}
if (videoItem case final RecVideoItemAppModel item) {
ThreePoint? tp = item.threePoint;
if (tp == null) {
SmartDialog.showToast("未能获取threePoint");
return;
}
if (tp.dislikeReasons == null && tp.feedbacks == null) {
SmartDialog.showToast(
"未能获取dislikeReasons或feedbacks",
);
return;
}
Widget actionButton(Reason? r, Reason? f) {
return SearchText(
text: r?.name ?? f?.name ?? '未知',
onTap: (_) async {
Get.back();
SmartDialog.showLoading(msg: '正在提交');
final res = await VideoHttp.feedDislike(
reasonId: r?.id,
feedbackId: f?.id,
id: item.param!,
goto: item.goto!,
);
}
SmartDialog.dismiss();
if (res.isSuccess) {
SmartDialog.showToast(
r?.toast ?? f!.toast!,
);
onRemove?.call();
} else {
res.toast();
}
},
);
}
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: .start,
children: [
if (tp.dislikeReasons != null) ...[
const Text('我不想看'),
const SizedBox(height: 5),
Wrap(
spacing: 8.0,
runSpacing: 8.0,
children: tp.dislikeReasons!.map((
item,
) {
return actionButton(item, null);
}).toList(),
),
],
if (tp.feedbacks != null) ...[
const SizedBox(height: 5),
const Text('反馈'),
const SizedBox(height: 5),
Wrap(
spacing: 8.0,
runSpacing: 8.0,
children: tp.feedbacks!.map((item) {
return actionButton(null, item);
}).toList(),
),
],
const Divider(),
Center(
child: FilledButton.tonal(
onPressed: () async {
SmartDialog.showLoading(
msg: '正在提交',
);
final res =
await VideoHttp.feedDislikeCancel(
id: item.param!,
goto: item.goto!,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res.isSuccess
? "成功"
: res.toString(),
);
Get.back();
},
style: FilledButton.styleFrom(
visualDensity:
VisualDensity.compact,
),
child: const Text("撤销"),
),
),
],
),
),
);
},
);
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 5),
const Text("web端暂不支持精细选择"),
const SizedBox(height: 5),
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: [
FilledButton.tonal(
onPressed: () async {
Get.back();
SmartDialog.showLoading(
msg: '正在提交',
);
final res =
await VideoHttp.dislikeVideo(
bvid: videoItem.bvid!,
type: true,
);
SmartDialog.dismiss();
if (res.isSuccess) {
SmartDialog.showToast('点踩成功');
onRemove?.call();
} else {
res.toast();
}
},
style: FilledButton.styleFrom(
visualDensity:
VisualDensity.compact,
),
child: const Text("点踩"),
),
FilledButton.tonal(
onPressed: () async {
Get.back();
SmartDialog.showLoading(
msg: '正在提交',
);
final res =
await VideoHttp.dislikeVideo(
bvid: videoItem.bvid!,
type: false,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res.isSuccess
? '取消踩'
: res.toString(),
);
},
style: FilledButton.styleFrom(
visualDensity:
VisualDensity.compact,
),
child: const Text("撤销"),
),
],
),
],
),
),
);
},
);
}
},
),
_VideoCustomAction(
'拉黑:${videoItem.owner.name}',
const Icon(MdiIcons.cancel, size: 16),
() => showDialog(
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('提示'),
content: Text(
'确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?'
'\n\n被拉黑的Up可以在隐私设置-黑名单管理中解除',
),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'点错了',
style: TextStyle(
color: Theme.of(
context,
).colorScheme.outline,
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: .start,
children: [
if (tp.dislikeReasons != null) ...[
const Text('我不想看'),
const SizedBox(height: 5),
Wrap(
spacing: 8.0,
runSpacing: 8.0,
children: tp.dislikeReasons!.map((
item,
) {
return actionButton(item, null);
}).toList(),
),
],
if (tp.feedbacks != null) ...[
const SizedBox(height: 5),
const Text('反馈'),
const SizedBox(height: 5),
Wrap(
spacing: 8.0,
runSpacing: 8.0,
children: tp.feedbacks!.map((item) {
return actionButton(null, item);
}).toList(),
),
],
const Divider(),
Center(
child: FilledButton.tonal(
onPressed: () async {
SmartDialog.showLoading(
msg: '正在提交',
);
final res =
await VideoHttp.feedDislikeCancel(
id: item.param!,
goto: item.goto!,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res.isSuccess
? "成功"
: res.toString(),
);
Get.back();
},
style: FilledButton.styleFrom(
visualDensity: VisualDensity.compact,
),
child: const Text("撤销"),
),
),
),
],
),
TextButton(
onPressed: () async {
Get.back();
final res = await VideoHttp.relationMod(
mid: videoItem.owner.mid!,
act: 5,
reSrc: 11,
);
if (res.isSuccess) {
onRemove?.call();
} else {
res.toast();
}
},
child: const Text('确认'),
),
],
),
);
},
),
),
);
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 5),
const Text("web端暂不支持精细选择"),
const SizedBox(height: 5),
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: [
FilledButton.tonal(
onPressed: () async {
Get.back();
SmartDialog.showLoading(
msg: '正在提交',
);
final res =
await VideoHttp.dislikeVideo(
bvid: videoItem.bvid!,
type: true,
);
SmartDialog.dismiss();
if (res.isSuccess) {
SmartDialog.showToast('点踩成功');
onRemove?.call();
} else {
res.toast();
}
},
style: FilledButton.styleFrom(
visualDensity:
VisualDensity.compact,
),
child: const Text("点踩"),
),
FilledButton.tonal(
onPressed: () async {
Get.back();
SmartDialog.showLoading(
msg: '正在提交',
);
final res =
await VideoHttp.dislikeVideo(
bvid: videoItem.bvid!,
type: false,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res.isSuccess
? '取消踩'
: res.toString(),
);
},
style: FilledButton.styleFrom(
visualDensity:
VisualDensity.compact,
),
child: const Text("撤销"),
),
],
),
],
),
),
);
},
);
}
},
),
_VideoCustomAction(
'拉黑:${videoItem.owner.name}',
const Icon(MdiIcons.cancel, size: 16),
() => showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('提示'),
content: Text(
'确定拉黑:${videoItem.owner.name}(${videoItem.owner.mid})?'
'\n\n被拉黑的Up可以在隐私设置-黑名单管理中解除',
),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'点错了',
style: TextStyle(
color: Theme.of(
context,
).colorScheme.outline,
),
),
),
TextButton(
onPressed: () async {
Get.back();
final res = await VideoHttp.relationMod(
mid: videoItem.owner.mid!,
act: 5,
reSrc: 11,
);
if (res.isSuccess) {
onRemove?.call();
} else {
res.toast();
}
},
child: const Text('确认'),
),
],
);
},
),
),
],
_VideoCustomAction(
"${MineController.anonymity.value ? '退出' : '进入'}无痕模式",
MineController.anonymity.value
? const Icon(MdiIcons.incognitoOff, size: 16)
: const Icon(MdiIcons.incognito, size: 16),
MineController.onChangeAnonymity,
),
]
.map(
(e) => PopupMenuItem(
height: menuItemHeight,
onTap: e.onTap,
child: Row(
children: [
e.icon,
const SizedBox(width: 6),
Text(e.title, style: const TextStyle(fontSize: 13)),
],
_VideoCustomAction(
"${MineController.anonymity.value ? '退出' : '进入'}无痕模式",
MineController.anonymity.value
? const Icon(MdiIcons.incognitoOff, size: 16)
: const Icon(MdiIcons.incognito, size: 16),
MineController.onChangeAnonymity,
),
]
.map(
(e) => PopupMenuItem(
height: menuItemHeight,
onTap: e.onTap,
child: Row(
children: [
e.icon,
const SizedBox(width: 6),
Text(e.title, style: const TextStyle(fontSize: 13)),
],
),
),
)
.toList(),
),
),
),
),
)
.toList(),
);
}
}