mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
@@ -28,6 +28,7 @@ void imageSaveDialog({
|
||||
return iconButton(
|
||||
icon: icon,
|
||||
iconSize: 20,
|
||||
tooltip: tooltip,
|
||||
onPressed: onPressed,
|
||||
);
|
||||
}
|
||||
@@ -57,19 +58,19 @@ void imageSaveDialog({
|
||||
Positioned(
|
||||
right: 8,
|
||||
top: 8,
|
||||
child: Container(
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black.withValues(alpha: 0.3),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const IconButton(
|
||||
child: IconButton(
|
||||
tooltip: '关闭',
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStatePropertyAll(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
Colors.black.withValues(alpha: 0.3),
|
||||
),
|
||||
padding: const WidgetStatePropertyAll(EdgeInsets.zero),
|
||||
),
|
||||
onPressed: SmartDialog.dismiss,
|
||||
icon: Icon(
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
color: Colors.white,
|
||||
|
||||
@@ -9,329 +9,25 @@ import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
||||
import 'package:PiliPlus/pages/video/ai_conclusion/view.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
class VideoCustomAction {
|
||||
class _VideoCustomAction {
|
||||
final String title;
|
||||
final Widget icon;
|
||||
final VoidCallback? onTap;
|
||||
const VideoCustomAction(this.title, this.icon, this.onTap);
|
||||
}
|
||||
|
||||
class VideoCustomActions {
|
||||
BaseSimpleVideoItemModel videoItem;
|
||||
BuildContext context;
|
||||
late List<VideoCustomAction> actions;
|
||||
VoidCallback? onRemove;
|
||||
|
||||
VideoCustomActions(this.videoItem, this.context, [this.onRemove]) {
|
||||
actions = [
|
||||
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),
|
||||
() async {
|
||||
var res = await UserHttp.toViewLater(bvid: videoItem.bvid);
|
||||
SmartDialog.showToast(res['msg']);
|
||||
},
|
||||
),
|
||||
VideoCustomAction(
|
||||
'AI总结',
|
||||
const Stack(
|
||||
alignment: Alignment.center,
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Icon(Icons.circle_outlined, size: 16),
|
||||
ExcludeSemantics(
|
||||
child: Text(
|
||||
'AI',
|
||||
style: TextStyle(
|
||||
fontSize: 8,
|
||||
height: 1,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
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) {
|
||||
final theme = Theme.of(context);
|
||||
return Dialog(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 420),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 14),
|
||||
child: AiConclusionPanel.buildContent(
|
||||
context,
|
||||
theme,
|
||||
res,
|
||||
tap: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
if (videoItem is! SpaceArchiveItem)
|
||||
VideoCustomAction(
|
||||
'访问:${videoItem.owner.name}',
|
||||
const Icon(MdiIcons.accountCircleOutline, size: 16),
|
||||
() => Get.toNamed('/member?mid=${videoItem.owner.mid}'),
|
||||
),
|
||||
if (videoItem is! SpaceArchiveItem)
|
||||
VideoCustomAction(
|
||||
'不感兴趣',
|
||||
const Icon(MdiIcons.thumbDownOutline, size: 16),
|
||||
() {
|
||||
String? accessKey = Accounts.get(AccountType.recommend).accessKey;
|
||||
if (accessKey == null || accessKey == "") {
|
||||
SmartDialog.showToast("请退出账号后重新登录");
|
||||
return;
|
||||
}
|
||||
if (videoItem case 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: '正在提交');
|
||||
var res = await VideoHttp.feedDislike(
|
||||
reasonId: r?.id,
|
||||
feedbackId: f?.id,
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status'] ? (r?.toast ?? f?.toast) : res['msg'],
|
||||
);
|
||||
if (res['status']) {
|
||||
onRemove?.call();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: 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: '正在提交');
|
||||
var res = await VideoHttp.feedDislikeCancel(
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status'] ? "成功" : res['msg'],
|
||||
);
|
||||
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: '正在提交');
|
||||
var res = await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: true,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status'] ? "点踩成功" : res['msg'],
|
||||
);
|
||||
if (res['status']) {
|
||||
onRemove?.call();
|
||||
}
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
child: const Text("点踩"),
|
||||
),
|
||||
FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(msg: '正在提交');
|
||||
var res = await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: false,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status'] ? "取消踩" : res['msg'],
|
||||
);
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
child: const Text("撤销"),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (videoItem is! SpaceArchiveItem)
|
||||
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();
|
||||
var res = await VideoHttp.relationMod(
|
||||
mid: videoItem.owner.mid!,
|
||||
act: 5,
|
||||
reSrc: 11,
|
||||
);
|
||||
if (res['status']) {
|
||||
onRemove?.call();
|
||||
}
|
||||
SmartDialog.showToast(res['msg'] ?? '成功');
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
VideoCustomAction(
|
||||
"${MineController.anonymity.value ? '退出' : '进入'}无痕模式",
|
||||
MineController.anonymity.value
|
||||
? const Icon(MdiIcons.incognitoOff, size: 16)
|
||||
: const Icon(MdiIcons.incognito, size: 16),
|
||||
MineController.onChangeAnonymity,
|
||||
),
|
||||
];
|
||||
}
|
||||
final VoidCallback onTap;
|
||||
const _VideoCustomAction(this.title, this.icon, this.onTap);
|
||||
}
|
||||
|
||||
class VideoPopupMenu extends StatelessWidget {
|
||||
final double? size;
|
||||
final double? iconSize;
|
||||
final double menuItemHeight;
|
||||
final dynamic videoItem;
|
||||
final BaseSimpleVideoItemModel videoItem;
|
||||
final VoidCallback? onRemove;
|
||||
|
||||
const VideoPopupMenu({
|
||||
@@ -349,7 +45,7 @@ class VideoPopupMenu extends StatelessWidget {
|
||||
child: SizedBox(
|
||||
width: size,
|
||||
height: size,
|
||||
child: PopupMenuButton<String>(
|
||||
child: PopupMenuButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(
|
||||
Icons.more_vert_outlined,
|
||||
@@ -357,20 +53,358 @@ class VideoPopupMenu extends StatelessWidget {
|
||||
size: iconSize,
|
||||
),
|
||||
position: PopupMenuPosition.under,
|
||||
itemBuilder: (BuildContext context) =>
|
||||
VideoCustomActions(videoItem, context, onRemove).actions.map((e) {
|
||||
return PopupMenuItem<Never>(
|
||||
height: menuItemHeight,
|
||||
onTap: e.onTap,
|
||||
child: Row(
|
||||
children: [
|
||||
e.icon,
|
||||
const SizedBox(width: 6),
|
||||
Text(e.title, style: const TextStyle(fontSize: 13)),
|
||||
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),
|
||||
() async {
|
||||
var res = await UserHttp.toViewLater(
|
||||
bvid: videoItem.bvid,
|
||||
);
|
||||
SmartDialog.showToast(res['msg']);
|
||||
},
|
||||
),
|
||||
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: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 420,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 14,
|
||||
),
|
||||
child: AiConclusionPanel.buildContent(
|
||||
context,
|
||||
Theme.of(context),
|
||||
res,
|
||||
tap: false,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
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 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: '正在提交');
|
||||
var res = await VideoHttp.feedDislike(
|
||||
reasonId: r?.id,
|
||||
feedbackId: f?.id,
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status']
|
||||
? (r?.toast ?? f?.toast)
|
||||
: res['msg'],
|
||||
);
|
||||
if (res['status']) {
|
||||
onRemove?.call();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
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: '正在提交',
|
||||
);
|
||||
var res =
|
||||
await VideoHttp.feedDislikeCancel(
|
||||
id: item.param!,
|
||||
goto: item.goto!,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status']
|
||||
? "成功"
|
||||
: res['msg'],
|
||||
);
|
||||
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: '正在提交',
|
||||
);
|
||||
var res =
|
||||
await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: true,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status']
|
||||
? "点踩成功"
|
||||
: res['msg'],
|
||||
);
|
||||
if (res['status']) {
|
||||
onRemove?.call();
|
||||
}
|
||||
},
|
||||
style: FilledButton.styleFrom(
|
||||
visualDensity:
|
||||
VisualDensity.compact,
|
||||
),
|
||||
child: const Text("点踩"),
|
||||
),
|
||||
FilledButton.tonal(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
SmartDialog.showLoading(
|
||||
msg: '正在提交',
|
||||
);
|
||||
var res =
|
||||
await VideoHttp.dislikeVideo(
|
||||
bvid: videoItem.bvid!,
|
||||
type: false,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(
|
||||
res['status']
|
||||
? "取消踩"
|
||||
: res['msg'],
|
||||
);
|
||||
},
|
||||
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();
|
||||
var res = await VideoHttp.relationMod(
|
||||
mid: videoItem.owner.mid!,
|
||||
act: 5,
|
||||
reSrc: 11,
|
||||
);
|
||||
if (res['status']) {
|
||||
onRemove?.call();
|
||||
}
|
||||
SmartDialog.showToast(res['msg'] ?? '成功');
|
||||
},
|
||||
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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -70,8 +70,7 @@ class Request {
|
||||
|
||||
String jsonData = json.encode({
|
||||
'3064': 1,
|
||||
'39c8':
|
||||
'${account is AnonymousAccount ? '333.1365' : '333.788'}.fp.risk',
|
||||
'39c8': '333.1387.fp.risk',
|
||||
'3c43': {
|
||||
'adca': 'Linux',
|
||||
'bfe9': randPngEnd.substring(randPngEnd.length - 50),
|
||||
|
||||
@@ -15,13 +15,9 @@ class Avatar extends Owner {
|
||||
}
|
||||
|
||||
class Pendant {
|
||||
int? pid;
|
||||
String? name;
|
||||
String? image;
|
||||
|
||||
Pendant.fromJson(Map<String, dynamic> json) {
|
||||
pid = json['pid'];
|
||||
name = json['name'];
|
||||
image = json['image'];
|
||||
}
|
||||
}
|
||||
@@ -39,35 +35,19 @@ class BaseOfficialVerify {
|
||||
class Vip {
|
||||
int? type;
|
||||
late int status;
|
||||
int? dueDate;
|
||||
Label? label;
|
||||
|
||||
Vip.fromJson(Map<String, dynamic> json) {
|
||||
type = json['type'] ?? json['vipType'];
|
||||
status = json['status'] ?? json['vipStatus'] ?? 0;
|
||||
dueDate = json['due_date'] ?? json['vipDueDate'];
|
||||
if (json['label'] != null) label = Label.fromJson(json['label']);
|
||||
}
|
||||
}
|
||||
|
||||
class Label {
|
||||
String? path;
|
||||
String? text;
|
||||
String? labelTheme;
|
||||
String? textColor;
|
||||
int? bgStyle;
|
||||
String? bgColor;
|
||||
String? borderColor;
|
||||
String? image;
|
||||
|
||||
Label.fromJson(Map<String, dynamic> json) {
|
||||
path = json['path'];
|
||||
text = json['text'];
|
||||
labelTheme = json['label_theme'];
|
||||
textColor = json['text_color'];
|
||||
bgStyle = json['bg_style'];
|
||||
bgColor = json['bg_color'];
|
||||
borderColor = json['border_color'];
|
||||
image = json['image'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,6 +385,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
},
|
||||
),
|
||||
Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
backgroundColor: Colors.transparent,
|
||||
appBar: _buildAppBar(isFullScreen),
|
||||
body: isPortrait
|
||||
|
||||
@@ -119,7 +119,7 @@ class _MemberVideoState extends State<MemberVideo>
|
||||
Obx(
|
||||
() => !_controller.isLocating.value
|
||||
? Positioned(
|
||||
right: kFloatingActionButtonMargin + padding.right,
|
||||
right: kFloatingActionButtonMargin,
|
||||
bottom: kFloatingActionButtonMargin + padding.bottom,
|
||||
child: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
|
||||
@@ -501,28 +501,24 @@ class _SavePanelState extends State<SavePanel> {
|
||||
GestureDetector(
|
||||
onTap: () => Utils.copyText(uri),
|
||||
child: Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
padding: const EdgeInsets.all(
|
||||
width: 88,
|
||||
height: 88,
|
||||
margin: const EdgeInsets.all(
|
||||
12,
|
||||
),
|
||||
child: Container(
|
||||
color: Get.isDarkMode
|
||||
? Colors.white
|
||||
: theme
|
||||
.colorScheme
|
||||
.surface,
|
||||
padding: const EdgeInsets.all(
|
||||
3,
|
||||
),
|
||||
child: PrettyQrView.data(
|
||||
data: uri,
|
||||
decoration:
|
||||
const PrettyQrDecoration(
|
||||
shape:
|
||||
PrettyQrSquaresSymbol(),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(
|
||||
3,
|
||||
),
|
||||
color: Get.isDarkMode
|
||||
? Colors.white
|
||||
: theme.colorScheme.surface,
|
||||
child: PrettyQrView.data(
|
||||
data: uri,
|
||||
decoration:
|
||||
const PrettyQrDecoration(
|
||||
shape:
|
||||
PrettyQrSquaresSymbol(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -162,7 +162,7 @@ List<SettingsModel> get playSettings => [
|
||||
),
|
||||
const SettingsModel(
|
||||
settingsType: SettingsType.sw1tch,
|
||||
title: '显示 SuperChat',
|
||||
title: '显示 SuperChat (醒目留言)',
|
||||
leading: Icon(Icons.live_tv),
|
||||
setKey: SettingBoxKey.showSuperChat,
|
||||
defaultVal: true,
|
||||
|
||||
@@ -28,6 +28,7 @@ class AiConclusionPanel extends CommonSlidePage {
|
||||
}) {
|
||||
return CustomScrollView(
|
||||
key: key,
|
||||
shrinkWrap: !tap,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
if (res.summary?.isNotEmpty == true) ...[
|
||||
@@ -57,7 +58,7 @@ class AiConclusionPanel extends CommonSlidePage {
|
||||
padding: EdgeInsets.only(
|
||||
left: 14,
|
||||
right: 14,
|
||||
bottom: MediaQuery.viewPaddingOf(context).bottom + 100,
|
||||
bottom: !tap ? 0 : MediaQuery.viewPaddingOf(context).bottom + 100,
|
||||
),
|
||||
sliver: SliverList.builder(
|
||||
itemCount: res.outline!.length,
|
||||
|
||||
@@ -47,13 +47,13 @@ class VideoReplyReplyPanel extends CommonSlidePage {
|
||||
@override
|
||||
State<VideoReplyReplyPanel> createState() => _VideoReplyReplyPanelState();
|
||||
|
||||
static Future<void>? toReply(
|
||||
int oid,
|
||||
int rootId,
|
||||
static Future<void>? toReply({
|
||||
required int oid,
|
||||
required int rootId,
|
||||
String? rpIdStr,
|
||||
int type,
|
||||
required int type,
|
||||
Uri? uri,
|
||||
) {
|
||||
}) {
|
||||
final rpId = rpIdStr == null ? null : int.tryParse(rpIdStr);
|
||||
return Get.to(
|
||||
arguments: {
|
||||
|
||||
@@ -1370,7 +1370,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
child = plPlayer(width: maxWidth, height: maxHeight, isPipMode: true);
|
||||
} else if (!videoDetailController.horizontalScreen) {
|
||||
child = childWhenDisabled;
|
||||
} else if (maxWidth > maxHeight * kScreenRatio) {
|
||||
} else if (maxWidth / maxHeight >= kScreenRatio) {
|
||||
child = childWhenDisabledLandscape;
|
||||
} else if (maxWidth * (9 / 16) < (2 / 5) * maxHeight) {
|
||||
child = childWhenDisabled;
|
||||
@@ -1742,7 +1742,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
showEpisodes: showEpisodes,
|
||||
onShowMemberPage: onShowMemberPage,
|
||||
isPortrait: isPortrait,
|
||||
isHorizontal: isHorizontal ?? width! > height! * kScreenRatio,
|
||||
isHorizontal: isHorizontal ?? width! / height! >= kScreenRatio,
|
||||
),
|
||||
if (needRelated &&
|
||||
videoDetailController
|
||||
|
||||
@@ -1157,10 +1157,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
final item = ctr.findSingleDanmaku(pos);
|
||||
if (item == null) {
|
||||
_suspendedDm?.suspend = false;
|
||||
_suspendedDm = null;
|
||||
_dmOffset.value = null;
|
||||
} else if (item != _suspendedDm) {
|
||||
_suspendedDm?.suspend = false;
|
||||
if (item.content.extra == null) {
|
||||
_suspendedDm = null;
|
||||
_dmOffset.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,11 +125,11 @@ abstract final class PiliScheme {
|
||||
int? rpid = int.tryParse(queryParameters['comment_root_id']!);
|
||||
if (oid != null && rpid != null) {
|
||||
VideoReplyReplyPanel.toReply(
|
||||
int.parse(oid),
|
||||
rpid,
|
||||
queryParameters['comment_secondary_id'],
|
||||
1,
|
||||
uri.replace(query: ''),
|
||||
oid: int.parse(oid),
|
||||
rootId: rpid,
|
||||
rpIdStr: queryParameters['comment_secondary_id'],
|
||||
type: 1,
|
||||
uri: uri.replace(query: ''),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -225,11 +225,12 @@ abstract final class PiliScheme {
|
||||
// int.parse(queryParameters['extraIntentId'] ?? '0');
|
||||
final enterUri = queryParameters['enterUri'];
|
||||
VideoReplyReplyPanel.toReply(
|
||||
oid,
|
||||
rootId,
|
||||
queryParameters['anchor'], // source_id
|
||||
type,
|
||||
enterUri != null
|
||||
oid: oid,
|
||||
rootId: rootId,
|
||||
rpIdStr:
|
||||
queryParameters['anchor'] ?? pathSegments[3], // source_id
|
||||
type: type,
|
||||
uri: enterUri != null
|
||||
? Uri.parse(enterUri)
|
||||
: const [11, 16, 17].contains(type)
|
||||
? Uri(
|
||||
@@ -270,11 +271,11 @@ abstract final class PiliScheme {
|
||||
int? rpid = int.tryParse(commentRootId);
|
||||
if (dynId != null && rpid != null) {
|
||||
VideoReplyReplyPanel.toReply(
|
||||
oid ?? int.parse(dynId),
|
||||
rpid,
|
||||
queryParameters['comment_secondary_id'],
|
||||
businessId ?? 17,
|
||||
uri.replace(query: ''),
|
||||
oid: oid ?? int.parse(dynId),
|
||||
rootId: rpid,
|
||||
rpIdStr: queryParameters['comment_secondary_id'],
|
||||
type: businessId ?? 17,
|
||||
uri: uri.replace(query: ''),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -647,11 +648,11 @@ abstract final class PiliScheme {
|
||||
final part = queryParameters['p'];
|
||||
if (rootIdStr != null) {
|
||||
VideoReplyReplyPanel.toReply(
|
||||
res.av ?? IdUtils.bv2av(res.bv!),
|
||||
int.parse(rootIdStr),
|
||||
queryParameters['comment_secondary_id'],
|
||||
1,
|
||||
uri.replace(query: part != null ? 'p=$part' : ''),
|
||||
oid: res.av ?? IdUtils.bv2av(res.bv!),
|
||||
rootId: int.parse(rootIdStr),
|
||||
rpIdStr: queryParameters['comment_secondary_id'],
|
||||
type: 1,
|
||||
uri: uri.replace(query: part != null ? 'p=$part' : ''),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -748,11 +749,11 @@ abstract final class PiliScheme {
|
||||
final pageType = queryParameters['pageType'];
|
||||
if (oid != null && root != null && pageType != null) {
|
||||
VideoReplyReplyPanel.toReply(
|
||||
int.parse(oid),
|
||||
int.parse(root),
|
||||
queryParameters['comment_secondary_id'],
|
||||
int.parse(pageType),
|
||||
Uri(scheme: 'bilibili', host: 'video', path: oid),
|
||||
oid: int.parse(oid),
|
||||
rootId: int.parse(root),
|
||||
rpIdStr: queryParameters['comment_secondary_id'],
|
||||
type: int.parse(pageType),
|
||||
uri: Uri(scheme: 'bilibili', host: 'video', path: oid),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user