mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-31 08:08:19 +08:00
opt pgc review
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -865,4 +865,8 @@ class Api {
|
|||||||
static const String pgcReviewDislike = '/pgc/review/action/dislike';
|
static const String pgcReviewDislike = '/pgc/review/action/dislike';
|
||||||
|
|
||||||
static const String pgcReviewPost = '/pgc/review/short/post';
|
static const String pgcReviewPost = '/pgc/review/short/post';
|
||||||
|
|
||||||
|
static const String pgcReviewMod = '/pgc/review/short/modify';
|
||||||
|
|
||||||
|
static const String pgcReviewDel = '/pgc/review/short/del';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,4 +200,48 @@ class BangumiHttp {
|
|||||||
return {'status': false, 'msg': res.data['message']};
|
return {'status': false, 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future pgcReviewMod({
|
||||||
|
required mediaId,
|
||||||
|
required int score,
|
||||||
|
required String content,
|
||||||
|
required reviewId,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.pgcReviewMod,
|
||||||
|
data: {
|
||||||
|
'media_id': mediaId,
|
||||||
|
'score': score,
|
||||||
|
'content': content,
|
||||||
|
'review_id': reviewId,
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
},
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future pgcReviewDel({
|
||||||
|
required mediaId,
|
||||||
|
required reviewId,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.pgcReviewDel,
|
||||||
|
data: {
|
||||||
|
'media_id': mediaId,
|
||||||
|
'review_id': reviewId,
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
},
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ class PgcReviewController
|
|||||||
final item = loadingState.value.data![index];
|
final item = loadingState.value.data![index];
|
||||||
item.stat?.disliked = isDislike ? 0 : 1;
|
item.stat?.disliked = isDislike ? 0 : 1;
|
||||||
if (!isDislike) {
|
if (!isDislike) {
|
||||||
|
if (item.stat?.liked == 1) {
|
||||||
|
item.stat!.likes = item.stat!.likes! - 1;
|
||||||
|
}
|
||||||
item.stat?.liked = 0;
|
item.stat?.liked = 0;
|
||||||
}
|
}
|
||||||
loadingState.refresh();
|
loadingState.refresh();
|
||||||
@@ -86,4 +89,19 @@ class PgcReviewController
|
|||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> onDel(int index, int? reviewId) async {
|
||||||
|
var res = await BangumiHttp.pgcReviewDel(
|
||||||
|
mediaId: mediaId,
|
||||||
|
reviewId: reviewId,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
loadingState
|
||||||
|
..value.data!.removeAt(index)
|
||||||
|
..refresh();
|
||||||
|
SmartDialog.showToast('删除成功');
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import 'package:PiliPlus/models/bangumi/pgc_review/list.dart';
|
|||||||
import 'package:PiliPlus/models/common/image_type.dart';
|
import 'package:PiliPlus/models/common/image_type.dart';
|
||||||
import 'package:PiliPlus/models/common/pgc_review_type.dart';
|
import 'package:PiliPlus/models/common/pgc_review_type.dart';
|
||||||
import 'package:PiliPlus/pages/pgc_review/child/controller.dart';
|
import 'package:PiliPlus/pages/pgc_review/child/controller.dart';
|
||||||
|
import 'package:PiliPlus/pages/pgc_review/post/view.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
|
import 'package:PiliPlus/utils/storage.dart' show Accounts;
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
@@ -19,10 +21,12 @@ class PgcReviewChildPage extends StatefulWidget {
|
|||||||
const PgcReviewChildPage({
|
const PgcReviewChildPage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.type,
|
required this.type,
|
||||||
|
required this.name,
|
||||||
required this.mediaId,
|
required this.mediaId,
|
||||||
});
|
});
|
||||||
|
|
||||||
final PgcReviewType type;
|
final PgcReviewType type;
|
||||||
|
final String name;
|
||||||
final dynamic mediaId;
|
final dynamic mediaId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -113,15 +117,74 @@ class _PgcReviewChildPageState extends State<PgcReviewChildPage>
|
|||||||
: null,
|
: null,
|
||||||
onLongPress: isLongReview
|
onLongPress: isLongReview
|
||||||
? null
|
? null
|
||||||
: () => showConfirmDialog(
|
: () => showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
title: '确定举报该点评?',
|
builder: (context) => AlertDialog(
|
||||||
onConfirm: () => Get.toNamed(
|
clipBehavior: Clip.hardEdge,
|
||||||
'/webview',
|
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
parameters: {
|
content: Column(
|
||||||
'url':
|
mainAxisSize: MainAxisSize.min,
|
||||||
'https://www.bilibili.com/appeal/?reviewId=${item.reviewId}&type=shortComment&mediaId=${widget.mediaId}'
|
children: [
|
||||||
},
|
if (item.author!.mid == Accounts.main.mid) ...[
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text(
|
||||||
|
'编辑',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
useSafeArea: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) {
|
||||||
|
return PgcReviewPostPanel(
|
||||||
|
name: widget.name,
|
||||||
|
mediaId: widget.mediaId,
|
||||||
|
reviewId: item.reviewId,
|
||||||
|
content: item.content,
|
||||||
|
score: item.score,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text(
|
||||||
|
'删除',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
showConfirmDialog(
|
||||||
|
context: context,
|
||||||
|
title: '删除短评,同时删除评分?',
|
||||||
|
onConfirm: () =>
|
||||||
|
_controller.onDel(index, item.reviewId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: const Text(
|
||||||
|
'举报',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
onTap: () => Get
|
||||||
|
..back()
|
||||||
|
..toNamed(
|
||||||
|
'/webview',
|
||||||
|
parameters: {
|
||||||
|
'url':
|
||||||
|
'https://www.bilibili.com/appeal/?reviewId=${item.reviewId}&type=shortComment&mediaId=${widget.mediaId}'
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|||||||
@@ -12,10 +12,17 @@ class PgcReviewPostPanel extends CommonCollapseSlidePage {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.mediaId,
|
required this.mediaId,
|
||||||
|
this.reviewId,
|
||||||
|
this.score,
|
||||||
|
this.content,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final dynamic mediaId;
|
final dynamic mediaId;
|
||||||
|
// modify
|
||||||
|
final dynamic reviewId;
|
||||||
|
final int? score;
|
||||||
|
final String? content;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<PgcReviewPostPanel> createState() => _PgcReviewPostPanelState();
|
State<PgcReviewPostPanel> createState() => _PgcReviewPostPanelState();
|
||||||
@@ -23,10 +30,11 @@ class PgcReviewPostPanel extends CommonCollapseSlidePage {
|
|||||||
|
|
||||||
class _PgcReviewPostPanelState
|
class _PgcReviewPostPanelState
|
||||||
extends CommonCollapseSlidePageState<PgcReviewPostPanel> {
|
extends CommonCollapseSlidePageState<PgcReviewPostPanel> {
|
||||||
final _controller = TextEditingController();
|
late final _controller = TextEditingController(text: widget.content);
|
||||||
final RxInt _score = 0.obs;
|
late final RxInt _score = (widget.score ?? 0).obs;
|
||||||
final RxBool _shareFeed = false.obs;
|
late final RxBool _shareFeed = false.obs;
|
||||||
final RxBool _enablePost = false.obs;
|
late final RxBool _enablePost = _isMod.obs;
|
||||||
|
late final _isMod = widget.reviewId != null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
@@ -134,36 +142,37 @@ class _PgcReviewPostPanelState
|
|||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
if (!_isMod)
|
||||||
padding: const EdgeInsets.only(left: 12, right: 12, bottom: 12),
|
Padding(
|
||||||
child: GestureDetector(
|
padding: const EdgeInsets.only(left: 12, right: 12, bottom: 12),
|
||||||
behavior: HitTestBehavior.opaque,
|
child: GestureDetector(
|
||||||
onTap: () => _shareFeed.value = !_shareFeed.value,
|
behavior: HitTestBehavior.opaque,
|
||||||
child: Obx(
|
onTap: () => _shareFeed.value = !_shareFeed.value,
|
||||||
() {
|
child: Obx(
|
||||||
Color color = _shareFeed.value
|
() {
|
||||||
? theme.colorScheme.primary
|
Color color = _shareFeed.value
|
||||||
: theme.colorScheme.outline;
|
? theme.colorScheme.primary
|
||||||
return Row(
|
: theme.colorScheme.outline;
|
||||||
mainAxisSize: MainAxisSize.min,
|
return Row(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
Icon(
|
children: [
|
||||||
size: 22,
|
Icon(
|
||||||
_shareFeed.value
|
size: 22,
|
||||||
? Icons.check_box_outlined
|
_shareFeed.value
|
||||||
: Icons.check_box_outline_blank_outlined,
|
? Icons.check_box_outlined
|
||||||
color: color,
|
: Icons.check_box_outline_blank_outlined,
|
||||||
),
|
color: color,
|
||||||
Text(
|
),
|
||||||
' 分享到动态',
|
Text(
|
||||||
style: TextStyle(color: color),
|
' 分享到动态',
|
||||||
),
|
style: TextStyle(color: color),
|
||||||
],
|
),
|
||||||
);
|
],
|
||||||
},
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
left: 12,
|
left: 12,
|
||||||
@@ -192,31 +201,46 @@ class _PgcReviewPostPanelState
|
|||||||
borderRadius: BorderRadius.all(Radius.circular(6)),
|
borderRadius: BorderRadius.all(Radius.circular(6)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: _enablePost.value
|
onPressed: _enablePost.value ? _onPost : null,
|
||||||
? () async {
|
child: _isMod ? const Text('编辑') : const Text('发布'),
|
||||||
if (!Accounts.main.isLogin) {
|
|
||||||
SmartDialog.showToast('账号未登录');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var res = await BangumiHttp.pgcReviewPost(
|
|
||||||
mediaId: widget.mediaId,
|
|
||||||
score: _score.value * 2,
|
|
||||||
content: _controller.text,
|
|
||||||
shareFeed: _shareFeed.value,
|
|
||||||
);
|
|
||||||
if (res['status']) {
|
|
||||||
Get.back();
|
|
||||||
SmartDialog.showToast('点评成功');
|
|
||||||
} else {
|
|
||||||
SmartDialog.showToast(res['msg']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: const Text('发布'),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onPost() async {
|
||||||
|
if (_isMod) {
|
||||||
|
var res = await BangumiHttp.pgcReviewMod(
|
||||||
|
mediaId: widget.mediaId,
|
||||||
|
score: _score.value * 2,
|
||||||
|
content: _controller.text,
|
||||||
|
reviewId: widget.reviewId,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
Get.back();
|
||||||
|
SmartDialog.showToast('编辑成功');
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Accounts.main.isLogin) {
|
||||||
|
SmartDialog.showToast('账号未登录');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var res = await BangumiHttp.pgcReviewPost(
|
||||||
|
mediaId: widget.mediaId,
|
||||||
|
score: _score.value * 2,
|
||||||
|
content: _controller.text,
|
||||||
|
shareFeed: _isMod ? false : _shareFeed.value,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
Get.back();
|
||||||
|
SmartDialog.showToast('点评成功');
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,11 @@ class _PgcReviewPageState extends State<PgcReviewPage>
|
|||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
children: PgcReviewType.values
|
children: PgcReviewType.values
|
||||||
.map((e) =>
|
.map((e) => PgcReviewChildPage(
|
||||||
PgcReviewChildPage(type: e, mediaId: widget.mediaId))
|
type: e,
|
||||||
|
name: widget.name,
|
||||||
|
mediaId: widget.mediaId,
|
||||||
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
? '追番'
|
? '追番'
|
||||||
: '追剧';
|
: '追剧';
|
||||||
|
|
||||||
BangumiInfoModel bangumiItem = Get.arguments['bangumiItem'];
|
final BangumiInfoModel bangumiItem = Get.arguments['bangumiItem'];
|
||||||
|
|
||||||
// 是否点赞
|
// 是否点赞
|
||||||
RxBool hasLike = false.obs;
|
RxBool hasLike = false.obs;
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
final GlobalKey relatedVideoPanelKey = GlobalKey();
|
final GlobalKey relatedVideoPanelKey = GlobalKey();
|
||||||
final GlobalKey videoPlayerKey = GlobalKey();
|
final GlobalKey videoPlayerKey = GlobalKey();
|
||||||
final GlobalKey videoReplyPanelKey = GlobalKey();
|
final GlobalKey videoReplyPanelKey = GlobalKey();
|
||||||
|
late final GlobalKey ugcPanelKey = GlobalKey();
|
||||||
|
late final GlobalKey pgcPanelKey = GlobalKey();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -1797,6 +1799,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
slivers: [
|
slivers: [
|
||||||
if (videoDetailController.videoType == SearchType.video) ...[
|
if (videoDetailController.videoType == SearchType.video) ...[
|
||||||
VideoIntroPanel(
|
VideoIntroPanel(
|
||||||
|
key: ugcPanelKey,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
showAiBottomSheet: showAiBottomSheet,
|
showAiBottomSheet: showAiBottomSheet,
|
||||||
showEpisodes: showEpisodes,
|
showEpisodes: showEpisodes,
|
||||||
@@ -1831,6 +1834,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
SearchType.media_bangumi)
|
SearchType.media_bangumi)
|
||||||
Obx(
|
Obx(
|
||||||
() => BangumiIntroPanel(
|
() => BangumiIntroPanel(
|
||||||
|
key: pgcPanelKey,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
cid: videoDetailController.cid.value,
|
cid: videoDetailController.cid.value,
|
||||||
showEpisodes: showEpisodes,
|
showEpisodes: showEpisodes,
|
||||||
|
|||||||
Reference in New Issue
Block a user