feat: 新增长按删评论功能

This commit is contained in:
orz12
2024-04-22 20:08:27 +08:00
parent 6661967276
commit 65ce59984d
5 changed files with 106 additions and 40 deletions

View File

@@ -120,6 +120,10 @@ class Api {
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/action.md // https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/action.md
static const String replyAdd = '/x/v2/reply/add'; static const String replyAdd = '/x/v2/reply/add';
// 删除评论
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/action.md
static const String replyDel = '/x/v2/reply/del';
// 用户(被)关注数、投稿数 // 用户(被)关注数、投稿数
// https://api.bilibili.com/x/relation/stat?vmid=697166795 // https://api.bilibili.com/x/relation/stat?vmid=697166795
static const String userStat = '/x/relation/stat'; static const String userStat = '/x/relation/stat';

View File

@@ -376,6 +376,25 @@ class VideoHttp {
} }
} }
static Future replyDel({
required int type,//replyType
required int oid,
required int rpid,
}) async {
var res = await Request().post(Api.replyDel, queryParameters: {
'type': type,//type.index
'oid': oid,
'rpid': rpid,
'csrf': await Request.getCsrf(),
});
log(res.toString());
if (res.data['code'] == 0) {
return {'status': true};
} else {
return {'status': false, 'msg': res.data['message']};
}
}
// 查询是否关注up // 查询是否关注up
static Future hasFollow({required int mid}) async { static Future hasFollow({required int mid}) async {
var res = await Request().get(Api.hasFollow, data: {'fid': mid}); var res = await Request().get(Api.hasFollow, data: {'fid': mid});
@@ -584,14 +603,11 @@ class VideoHttp {
} }
} }
if (subtitlesVtt.isNotEmpty) { if (subtitlesVtt.isNotEmpty) {
subtitlesVtt.insert(0, { subtitlesVtt.insert(0, {'language': '', 'title': '关闭字幕', 'text': ""});
'language': '',
'title': '关闭字幕',
'text': ""
});
} }
return subtitlesVtt; return subtitlesVtt;
} }
// 视频排行 // 视频排行
static Future getRankVideoList(int rid) async { static Future getRankVideoList(int rid) async {
try { try {

View File

@@ -23,18 +23,16 @@ class ReplyData {
page = ReplyPage.fromJson(json['page']); page = ReplyPage.fromJson(json['page']);
config = ReplyConfig.fromJson(json['config']); config = ReplyConfig.fromJson(json['config']);
replies = json['replies'] != null replies = json['replies'] != null
? json['replies'] ? List<ReplyItemModel>.from(json['replies']
.map<ReplyItemModel>( .map<ReplyItemModel>(
(item) => ReplyItemModel.fromJson(item, json['upper']['mid'])) (item) => ReplyItemModel.fromJson(item, json['upper']['mid'])))
.toList() : <ReplyItemModel>[];
: [];
topReplies = json['top_replies'] != null topReplies = json['top_replies'] != null
? json['top_replies'] ? List<ReplyItemModel>.from(json['top_replies']
.map<ReplyItemModel>((item) => ReplyItemModel.fromJson( .map<ReplyItemModel>((item) => ReplyItemModel.fromJson(
item, json['upper']['mid'], item, json['upper']['mid'],
isTopStatus: true)) isTopStatus: true)))
.toList() : <ReplyItemModel>[];
: [];
upper = ReplyUpper.fromJson(json['upper']); upper = ReplyUpper.fromJson(json['upper']);
} }
} }

View File

@@ -53,7 +53,7 @@ class ReplyItemModel {
int? action; int? action;
ReplyMember? member; ReplyMember? member;
ReplyContent? content; ReplyContent? content;
List? replies; List<ReplyItemModel>? replies;
int? assist; int? assist;
UpAction? upAction; UpAction? upAction;
bool? invisible; bool? invisible;
@@ -85,10 +85,9 @@ class ReplyItemModel {
member = ReplyMember.fromJson(json['member']); member = ReplyMember.fromJson(json['member']);
content = ReplyContent.fromJson(json['content']); content = ReplyContent.fromJson(json['content']);
replies = json['replies'] != null replies = json['replies'] != null
? json['replies'] ? List<ReplyItemModel>.from(json['replies']
.map((item) => ReplyItemModel.fromJson(item, upperMid)) .map((item) => ReplyItemModel.fromJson(item, upperMid)))
.toList() : <ReplyItemModel>[];
: [];
assist = json['assist']; assist = json['assist'];
upAction = UpAction.fromJson(json['up_action']); upAction = UpAction.fromJson(json['up_action']);
invisible = json['invisible']; invisible = json['invisible'];

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/http/video.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@@ -54,7 +55,7 @@ class ReplyItem extends StatelessWidget {
useRootNavigator: true, useRootNavigator: true,
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return MorePanel(item: replyItem); return MorePanel(item: replyItem!);
}, },
); );
}, },
@@ -273,6 +274,7 @@ class ReplyItem extends StatelessWidget {
onPressed: () { onPressed: () {
feedBack(); feedBack();
showModalBottomSheet( showModalBottomSheet(
isDismissible: false,
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: (builder) { builder: (builder) {
@@ -347,7 +349,7 @@ class ReplyItemRow extends StatelessWidget {
this.replyItem, this.replyItem,
this.replyReply, this.replyReply,
}); });
final List? replies; final List<ReplyItemModel>? replies;
ReplyControl? replyControl; ReplyControl? replyControl;
// int? f_rpid; // int? f_rpid;
ReplyItemModel? replyItem; ReplyItemModel? replyItem;
@@ -392,9 +394,8 @@ class ReplyItemRow extends StatelessWidget {
i == 0 && (extraRow == 1 || replies!.length > 1) ? 4 : 6, i == 0 && (extraRow == 1 || replies!.length > 1) ? 4 : 6,
), ),
child: Semantics( child: Semantics(
label: replies![i].member.uname + label:
' ' + '${replies![i].member!.uname} ${replies![i].content!.message}',
replies![i].content.message,
excludeSemantics: true, excludeSemantics: true,
child: Text.rich( child: Text.rich(
style: TextStyle( style: TextStyle(
@@ -412,7 +413,7 @@ class ReplyItemRow extends StatelessWidget {
TextSpan( TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: replies![i].member.uname + ' ', text: '${replies![i].member!.uname} ',
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
@@ -423,16 +424,16 @@ class ReplyItemRow extends StatelessWidget {
..onTap = () { ..onTap = () {
feedBack(); feedBack();
final String heroTag = Utils.makeHeroTag( final String heroTag = Utils.makeHeroTag(
replies![i].member.mid); replies![i].member!.mid);
Get.toNamed( Get.toNamed(
'/member?mid=${replies![i].member.mid}', '/member?mid=${replies![i].member!.mid}',
arguments: { arguments: {
'face': replies![i].member.avatar, 'face': replies![i].member!.avatar,
'heroTag': heroTag 'heroTag': heroTag
}); });
}, },
), ),
if (replies![i].isUp) if (replies![i].isUp!)
const WidgetSpan( const WidgetSpan(
alignment: PlaceholderAlignment.top, alignment: PlaceholderAlignment.top,
child: PBadge( child: PBadge(
@@ -971,11 +972,11 @@ InlineSpan buildContent(
} }
class MorePanel extends StatelessWidget { class MorePanel extends StatelessWidget {
final dynamic item; final ReplyItemModel item;
const MorePanel({super.key, required this.item}); const MorePanel({super.key, required this.item});
Future<dynamic> menuActionHandler(String type) async { Future<dynamic> menuActionHandler(String type) async {
String message = item.content.message ?? item.content; String message = item.content?.message ?? '';
switch (type) { switch (type) {
case 'copyAll': case 'copyAll':
await Clipboard.setData(ClipboardData(text: message)); await Clipboard.setData(ClipboardData(text: message));
@@ -1000,9 +1001,46 @@ class MorePanel extends StatelessWidget {
// case 'report': // case 'report':
// SmartDialog.showToast('举报'); // SmartDialog.showToast('举报');
// break; // break;
// case 'delete': case 'delete':
// SmartDialog.showToast('删除'); //弹出确认提示:
// break; bool? isDelete = await showDialog<bool>(
context: Get.context!,
builder: (context) {
return AlertDialog(
title: const Text('删除评论(测试)'),
content:
Text('确定尝试删除这条评论吗?\n\n$message\n\n注:只能删除自己的评论,或自己管理的评论区下的评论'),
actions: <Widget>[
TextButton(
onPressed: () {
Get.back(result: false);
},
child: const Text('取消'),
),
TextButton(
onPressed: () {
Get.back(result: true);
},
child: const Text('确定'),
),
],
);
},
);
if (isDelete == null || !isDelete) {
return;
}
SmartDialog.showLoading(msg: '删除中...');
var result = await VideoHttp.replyDel(
type: item.type!, oid: item.oid!, rpid: item.rpid!);
SmartDialog.dismiss();
if (result['status']) {
SmartDialog.showToast('删除成功,请刷新');
// Get.back();
} else {
SmartDialog.showToast('删除失败, ${result["msg"]}');
}
break;
default: default:
} }
} }
@@ -1011,7 +1049,12 @@ class MorePanel extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Color errorColor = Theme.of(context).colorScheme.error; Color errorColor = Theme.of(context).colorScheme.error;
return Container( return Container(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), padding: EdgeInsets.only(
bottom: MediaQueryData.fromView(
WidgetsBinding.instance.platformDispatcher.views.single)
.padding
.bottom +
20),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -1031,6 +1074,18 @@ class MorePanel extends StatelessWidget {
), ),
), ),
), ),
// 已登录用户才显示删除
if (GStrorage.userInfo.get('userInfoCache') != null)
ListTile(
onTap: () async => await menuActionHandler('delete'),
minLeadingWidth: 0,
leading: Icon(Icons.delete_outlined, color: errorColor, size: 19),
title: Text('删除',
style: Theme.of(context)
.textTheme
.titleSmall!
.copyWith(color: errorColor)),
),
ListTile( ListTile(
onTap: () async => await menuActionHandler('copyAll'), onTap: () async => await menuActionHandler('copyAll'),
minLeadingWidth: 0, minLeadingWidth: 0,
@@ -1055,12 +1110,6 @@ class MorePanel extends StatelessWidget {
// leading: Icon(Icons.report_outlined, color: errorColor), // leading: Icon(Icons.report_outlined, color: errorColor),
// title: Text('举报', style: TextStyle(color: errorColor)), // title: Text('举报', style: TextStyle(color: errorColor)),
// ), // ),
// ListTile(
// onTap: () async => await menuActionHandler('del'),
// minLeadingWidth: 0,
// leading: Icon(Icons.delete_outline, color: errorColor),
// title: Text('删除', style: TextStyle(color: errorColor)),
// ),
], ],
), ),
); );