opt: resCode, post panel

fix: bangumi panel

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-11-25 20:47:05 +08:00
parent bae395c5d0
commit 2fc4760269
12 changed files with 329 additions and 404 deletions

View File

@@ -158,7 +158,9 @@ class _ListSheetContentState extends State<ListSheetContent>
late String title;
if (episode.runtimeType.toString() == "EpisodeItem") {
if (episode.longTitle != null && episode.longTitle != "") {
title = "${(episode.title ?? '${index + 1}')}话 ${episode.longTitle!}";
dynamic leading = episode.title ?? index + 1;
title =
"${Utils.isStringNumeric(leading) ? '$leading话' : leading} ${episode.longTitle!}";
} else {
title = episode.title!;
}
@@ -255,13 +257,12 @@ class _ListSheetContentState extends State<ListSheetContent>
'assets/images/big-vip.png',
height: 20,
semanticLabel: "大会员",
),
if (episode.badge != '会员') Text(episode.badge),
)
else
Text(episode.badge),
const SizedBox(width: 10),
],
if (!(episode.runtimeType.toString() == 'EpisodeItem' &&
(episode.longTitle != null && episode.longTitle != '')))
Text('${index + 1}/$length'),
if (episode is! bangumi.EpisodeItem) Text('${index + 1}/$length'),
],
),
);

View File

@@ -1,3 +1,6 @@
import 'package:PiliPalaX/common/widgets/stat/danmu.dart';
import 'package:PiliPalaX/common/widgets/stat/view.dart';
import 'package:PiliPalaX/common/widgets/video_popup_menu.dart';
import 'package:PiliPalaX/models/space_archive/item.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -14,163 +17,98 @@ class VideoCardHMemberVideo extends StatelessWidget {
required this.videoItem,
this.longPress,
this.longPressEnd,
this.source = 'normal',
this.showOwner = true,
this.showView = true,
this.showDanmaku = true,
this.showPubdate = false,
});
final Item videoItem;
final Function()? longPress;
final Function()? longPressEnd;
final String source;
final bool showOwner;
final bool showView;
final bool showDanmaku;
final bool showPubdate;
@override
Widget build(BuildContext context) {
final int aid = int.tryParse(videoItem.param ?? '') ?? -1;
final String bvid = videoItem.bvid ?? '';
String type = 'video';
// try {
// type = videoItem.type;
// } catch (_) {}
// List<VideoCustomAction> actions =
// VideoCustomActions(videoItem, context).actions;
final String heroTag = Utils.makeHeroTag(aid);
return Stack(children: [
Semantics(
// label: Utils.videoItemSemantics(videoItem),
excludeSemantics: true,
// customSemanticsActions: <CustomSemanticsAction, void Function()>{
// for (var item in actions)
// CustomSemanticsAction(label: item.title): item.onTap!,
// },
child: InkWell(
borderRadius: BorderRadius.circular(12),
onLongPress: () {
if (longPress != null) {
longPress!();
}
},
onTap: () async {
if (type == 'ketang') {
SmartDialog.showToast('课堂视频暂不支持播放');
return;
}
try {
// PiliScheme.routePush(Uri.parse(videoItem.smallCoverV5.base.uri));
// final int cid =
// videoItem.smallCoverV5.base.playerArgs.cid.toInt() ??
// await SearchHttp.ab2c(aid: aid, bvid: bvid);
Get.toNamed('/video?bvid=$bvid&cid=${videoItem.firstCid}',
arguments: {'heroTag': heroTag});
// Get.toNamed('/video?bvid=$bvid&cid=$cid',
// arguments: {'videoItem': videoItem, 'heroTag': heroTag});
} catch (err) {
SmartDialog.showToast(err.toString());
}
},
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints boxConstraints) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (BuildContext context,
BoxConstraints boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.cover,
width: maxWidth,
height: maxHeight,
),
InkWell(
borderRadius: BorderRadius.circular(12),
onLongPress: () {
if (longPress != null) {
longPress!();
}
},
onTap: () async {
try {
Get.toNamed('/video?bvid=$bvid&cid=${videoItem.firstCid}',
arguments: {'heroTag': heroTag});
} catch (err) {
SmartDialog.showToast(err.toString());
}
},
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints boxConstraints) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder:
(BuildContext context, BoxConstraints boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
children: [
Hero(
tag: heroTag,
child: NetworkImgLayer(
src: videoItem.cover,
width: maxWidth,
height: maxHeight,
),
if (videoItem.duration != null)
PBadge(
text: Utils.timeFormat(videoItem.duration),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
if (type != 'video')
PBadge(
text: type,
left: 6.0,
bottom: 6.0,
type: 'primary',
),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// pBadge(videoItem.rcmdReason.content, context,
// 6.0, 6.0, null, null),
],
);
},
),
),
if (videoItem.duration != null)
PBadge(
text: Utils.timeFormat(videoItem.duration),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
],
);
},
),
VideoContent(
videoItem: videoItem,
source: source,
showOwner: showOwner,
showView: showView,
showDanmaku: showDanmaku,
showPubdate: showPubdate,
)
],
);
},
),
),
VideoContent(
videoItem: videoItem,
)
],
);
},
),
),
Positioned(
bottom: 0,
right: 0,
child: VideoPopupMenu(
size: 29,
iconSize: 17,
actions: VideoCustomActions(videoItem, context).actions,
),
),
// if (source == 'normal')
// Positioned(
// bottom: 0,
// right: 0,
// child: VideoPopupMenu(
// size: 29,
// iconSize: 17,
// actions: actions,
// ),
// ),
]);
}
}
class VideoContent extends StatelessWidget {
final Item videoItem;
final String source;
final bool showOwner;
final bool showView;
final bool showDanmaku;
final bool showPubdate;
const VideoContent({
super.key,
required this.videoItem,
this.source = 'normal',
this.showOwner = true,
this.showView = true,
this.showDanmaku = true,
this.showPubdate = false,
});
@override
Widget build(BuildContext context) {
// String pubdate = showPubdate
// ? Utils.dateFormat(videoItem.pubdate!, formatType: 'day')
// : '';
// if (pubdate != '') pubdate += ' ';
return Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 6, 0),
@@ -193,39 +131,8 @@ class VideoContent extends StatelessWidget {
),
),
],
// const Spacer(),
// if (videoItem.rcmdReason != null &&
// videoItem.rcmdReason.content != '')
// Container(
// padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5),
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(4),
// border: Border.all(
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// child: Text(
// videoItem.rcmdReason.content,
// style: TextStyle(
// fontSize: 9,
// color: Theme.of(context).colorScheme.surfaceTint),
// ),
// ),
// const SizedBox(height: 4),
if (showOwner || showPubdate)
Text(
videoItem.publishTimeText ?? '',
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
height: 1,
color: Theme.of(context).colorScheme.outline,
overflow: TextOverflow.clip,
),
),
const SizedBox(height: 3),
Text(
'${videoItem.viewContent} · ${videoItem.danmaku}',
videoItem.publishTimeText ?? '',
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.w400,
@@ -235,24 +142,20 @@ class VideoContent extends StatelessWidget {
overflow: TextOverflow.clip,
),
),
// Row(
// children: [
// if (showView) ...[
// StatView(
// theme: 'gray',
// view: videoItem.stat.view as int,
// ),
// const SizedBox(width: 8),
// ],
// if (showDanmaku)
// StatDanMu(
// theme: 'gray',
// danmu: videoItem.stat.danmu as int,
// ),
// const Spacer(),
// if (source == 'normal') const SizedBox(width: 24),
// ],
// ),
const SizedBox(height: 3),
Row(
children: [
StatView(
theme: 'gray',
view: videoItem.viewContent,
),
const SizedBox(width: 8),
StatDanMu(
theme: 'gray',
danmu: videoItem.danmaku,
),
],
),
],
),
),

View File

@@ -20,11 +20,6 @@ class VideoCardVMemberHome extends StatelessWidget {
this.longPressEnd,
});
bool isStringNumeric(String str) {
RegExp numericRegex = RegExp(r'^\d+$');
return numericRegex.hasMatch(str);
}
void onPushDetail(heroTag) async {
String goto = videoItem.goto ?? '';
switch (goto) {

View File

@@ -9,6 +9,7 @@ import '../../http/video.dart';
import '../../models/home/rcmd/result.dart';
import '../../pages/mine/controller.dart';
import '../../utils/storage.dart';
import 'package:PiliPalaX/models/space_archive/item.dart';
class VideoCustomAction {
String title;
@@ -47,211 +48,215 @@ class VideoCustomActions {
SmartDialog.showToast(res['msg']);
},
),
VideoCustomAction(
'访问:${videoItem.owner.name}',
'visit',
Icon(MdiIcons.accountCircleOutline, size: 16),
() async {
Get.toNamed('/member?mid=${videoItem.owner.mid}', arguments: {
// 'face': videoItem.owner.face,
'heroTag': '${videoItem.owner.mid}',
});
},
),
VideoCustomAction(
'不感兴趣', 'dislike', Icon(MdiIcons.thumbDownOutline, size: 16),
if (videoItem is! Item)
VideoCustomAction(
'访问:${videoItem.owner.name}',
'visit',
Icon(MdiIcons.accountCircleOutline, size: 16),
() async {
String? accessKey = GStorage.localCache
.get(LocalCacheKey.accessKey, defaultValue: {})['value'];
if (accessKey == null || accessKey == "") {
SmartDialog.showToast("请退出账号后重新登录");
return;
}
if (videoItem is RecVideoItemAppModel) {
RecVideoItemAppModel v = videoItem as RecVideoItemAppModel;
ThreePoint? tp = v.threePoint;
if (tp == null) {
SmartDialog.showToast("未能获取threePoint");
return;
}
if (tp.dislikeReasons == null && tp.feedbacks == null) {
SmartDialog.showToast("未能获取dislikeReasons或feedbacks");
return;
}
Widget actionButton(DislikeReason? r, FeedbackReason? f) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 12.0, vertical: 0.0),
),
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.feedDislike(
reasonId: r?.id,
feedbackId: f?.id,
id: v.param!,
goto: v.goto!,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? (r?.toast ?? f?.toast) : res['msg']);
Get.back();
},
child: Text(r?.name ?? f?.name ?? '未知'),
);
}
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('请选择'),
content: SingleChildScrollView(
child: Column(
children: [
if (tp.dislikeReasons != null)
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('我不想看'),
),
if (tp.dislikeReasons != null)
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: tp.dislikeReasons!.map((item) {
return actionButton(item, null);
}).toList(),
),
if (tp.feedbacks != null)
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('反馈'),
),
if (tp.feedbacks != null)
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: tp.feedbacks!.map((item) {
return actionButton(null, item);
}).toList(),
),
//分割线
const Divider(),
ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.feedDislikeCancel(
// reasonId: r?.id,
// feedbackId: f?.id,
id: v.param!,
goto: v.goto!,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? "成功" : res['msg']);
Get.back();
},
child: const Text("撤销"),
),
],
),
),
);
},
);
} else {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('点踩该视频?'),
content: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 5),
const Text("web端暂不支持精细选择"),
const SizedBox(height: 5),
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: [
ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.dislikeVideo(
bvid: videoItem.bvid as String, type: true);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? "点踩成功" : res['msg']);
Get.back();
},
child: const Text("点踩"),
),
ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.dislikeVideo(
bvid: videoItem.bvid as String, type: false);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? "取消踩" : res['msg']);
Get.back();
},
child: const Text("撤销"),
),
],
)
],
),
),
);
},
);
}
}),
VideoCustomAction('拉黑:${videoItem.owner.name}', 'block',
Icon(MdiIcons.cancel, size: 16), () async {
await 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 {
var res = await VideoHttp.relationMod(
mid: videoItem.owner.mid,
act: 5,
reSrc: 11,
);
List<int> blackMidsList = GStorage.localCache
.get(LocalCacheKey.blackMidsList, defaultValue: [-1])
.map<int>((i) => i as int)
.toList();
blackMidsList.insert(0, videoItem.owner.mid);
GStorage.localCache
.put(LocalCacheKey.blackMidsList, blackMidsList);
Get.back();
SmartDialog.showToast(res['msg'] ?? '成功');
},
child: const Text('确认'),
)
],
);
Get.toNamed('/member?mid=${videoItem.owner.mid}', arguments: {
// 'face': videoItem.owner.face,
'heroTag': '${videoItem.owner.mid}',
});
},
);
}),
),
if (videoItem is! Item)
VideoCustomAction(
'不感兴趣', 'dislike', Icon(MdiIcons.thumbDownOutline, size: 16),
() async {
String? accessKey = GStorage.localCache
.get(LocalCacheKey.accessKey, defaultValue: {})['value'];
if (accessKey == null || accessKey == "") {
SmartDialog.showToast("请退出账号后重新登录");
return;
}
if (videoItem is RecVideoItemAppModel) {
RecVideoItemAppModel v = videoItem as RecVideoItemAppModel;
ThreePoint? tp = v.threePoint;
if (tp == null) {
SmartDialog.showToast("未能获取threePoint");
return;
}
if (tp.dislikeReasons == null && tp.feedbacks == null) {
SmartDialog.showToast("未能获取dislikeReasons或feedbacks");
return;
}
Widget actionButton(DislikeReason? r, FeedbackReason? f) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 12.0, vertical: 0.0),
),
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.feedDislike(
reasonId: r?.id,
feedbackId: f?.id,
id: v.param!,
goto: v.goto!,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? (r?.toast ?? f?.toast) : res['msg']);
Get.back();
},
child: Text(r?.name ?? f?.name ?? '未知'),
);
}
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('请选择'),
content: SingleChildScrollView(
child: Column(
children: [
if (tp.dislikeReasons != null)
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('我不想看'),
),
if (tp.dislikeReasons != null)
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: tp.dislikeReasons!.map((item) {
return actionButton(item, null);
}).toList(),
),
if (tp.feedbacks != null)
const Padding(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: Text('反馈'),
),
if (tp.feedbacks != null)
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: tp.feedbacks!.map((item) {
return actionButton(null, item);
}).toList(),
),
//分割线
const Divider(),
ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.feedDislikeCancel(
// reasonId: r?.id,
// feedbackId: f?.id,
id: v.param!,
goto: v.goto!,
);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? "成功" : res['msg']);
Get.back();
},
child: const Text("撤销"),
),
],
),
),
);
},
);
} else {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('点踩该视频?'),
content: SingleChildScrollView(
child: Column(
children: [
const SizedBox(height: 5),
const Text("web端暂不支持精细选择"),
const SizedBox(height: 5),
Wrap(
spacing: 5.0,
runSpacing: 2.0,
children: [
ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.dislikeVideo(
bvid: videoItem.bvid as String, type: true);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? "点踩成功" : res['msg']);
Get.back();
},
child: const Text("点踩"),
),
ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '正在提交');
var res = await VideoHttp.dislikeVideo(
bvid: videoItem.bvid as String,
type: false);
SmartDialog.dismiss();
SmartDialog.showToast(
res['status'] ? "取消踩" : res['msg']);
Get.back();
},
child: const Text("撤销"),
),
],
)
],
),
),
);
},
);
}
}),
if (videoItem is! Item)
VideoCustomAction('拉黑:${videoItem.owner.name}', 'block',
Icon(MdiIcons.cancel, size: 16), () async {
await 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 {
var res = await VideoHttp.relationMod(
mid: videoItem.owner.mid,
act: 5,
reSrc: 11,
);
List<int> blackMidsList = GStorage.localCache
.get(LocalCacheKey.blackMidsList, defaultValue: [-1])
.map<int>((i) => i as int)
.toList();
blackMidsList.insert(0, videoItem.owner.mid);
GStorage.localCache
.put(LocalCacheKey.blackMidsList, blackMidsList);
Get.back();
SmartDialog.showToast(res['msg'] ?? '成功');
},
child: const Text('确认'),
)
],
);
},
);
}),
VideoCustomAction(
"${MineController.anonymity ? '退出' : '进入'}无痕模式",
'anonymity',