feat: reply vote

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-07-04 18:04:46 +08:00
parent fd017e0581
commit 0036b58aab
10 changed files with 319 additions and 192 deletions

View File

@@ -2,10 +2,12 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart';
import 'package:PiliPlus/grpc/reply.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/pages/video/reply/vote/reply_vote_mixin.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:get/get.dart';
abstract class CommonDynController extends ReplyController<MainListReply> {
abstract class CommonDynController extends ReplyController<MainListReply>
with ReplyVoteMixin {
int get oid;
int get replyType;

View File

@@ -10,6 +10,7 @@ import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/enum_with_label.dart';
import 'package:PiliPlus/pages/common/dyn/common_dyn_controller.dart';
import 'package:PiliPlus/pages/common/fab_mixin.dart';
import 'package:PiliPlus/pages/video/reply/vote/reply_vote_item.dart';
import 'package:PiliPlus/pages/video/reply/widgets/reply_item_grpc.dart';
import 'package:PiliPlus/pages/video/reply_reply/view.dart';
import 'package:PiliPlus/utils/extension/num_ext.dart';
@@ -120,62 +121,78 @@ mixin CommonDynPageMixin<T extends StatefulWidget>
}
Widget replyList(LoadingState<List<ReplyInfo>?> loadingState) {
return switch (loadingState) {
Loading() => SliverList.builder(
itemCount: 12,
itemBuilder: (context, index) => const VideoReplySkeleton(),
),
Success(:final response) =>
response != null && response.isNotEmpty
? SliverList.builder(
itemCount: response.length + 1,
itemBuilder: (context, index) {
if (index == response.length) {
controller.onLoadMore();
return Container(
alignment: Alignment.center,
margin: EdgeInsets.only(bottom: padding.bottom),
height: 125,
child: Text(
controller.isEnd ? '没有更多了' : '加载中...',
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
),
),
);
} else {
return ReplyItemGrpc(
replyItem: response[index],
replyLevel: 1,
replyReply: (replyItem, id) =>
replyReply(context, replyItem, id),
onReply: controller.onReply,
onDelete: (item, subIndex) =>
controller.onRemove(index, item, subIndex),
upMid: controller.upMid,
onViewImage: hideFab,
onCheckReply: (item) =>
controller.onCheckReply(item, isManual: true),
onToggleTop: (item) => controller.onToggleTop(
item,
index,
controller.oid,
controller.replyType,
),
);
}
},
)
: HttpError(
errMsg: '还没有评论',
onReload: controller.onReload,
),
Error(:final errMsg) => HttpError(
errMsg: errMsg,
onReload: controller.onReload,
),
};
switch (loadingState) {
case Loading():
return SliverList.builder(
itemCount: 12,
itemBuilder: (context, index) => const VideoReplySkeleton(),
);
case Success(:final response):
if (response != null && response.isNotEmpty) {
var count = response.length + 1;
final voteCard = controller.voteCard;
final hasVote = voteCard != null;
if (hasVote) {
count++;
}
return SliverList.builder(
itemCount: count,
itemBuilder: (context, index) {
if (hasVote) {
if (index == 0) {
return buildVoteCard(context, theme.colorScheme, voteCard);
} else {
index--;
}
}
if (index == response.length) {
controller.onLoadMore();
return Container(
alignment: Alignment.center,
margin: EdgeInsets.only(bottom: padding.bottom),
height: 125,
child: Text(
controller.isEnd ? '没有更多了' : '加载中...',
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
),
),
);
} else {
return ReplyItemGrpc(
replyItem: response[index],
replyLevel: 1,
replyReply: (replyItem, id) =>
replyReply(context, replyItem, id),
onReply: controller.onReply,
onDelete: (item, subIndex) =>
controller.onRemove(index, item, subIndex),
upMid: controller.upMid,
onViewImage: hideFab,
onCheckReply: (item) =>
controller.onCheckReply(item, isManual: true),
onToggleTop: (item) => controller.onToggleTop(
item,
index,
controller.oid,
controller.replyType,
),
);
}
},
);
}
return HttpError(
errMsg: '还没有评论',
onReload: controller.onReload,
);
case Error(:final errMsg):
return HttpError(
errMsg: errMsg,
onReload: controller.onReload,
);
}
}
void replyReply(BuildContext context, ReplyInfo replyItem, int? id) {

View File

@@ -57,16 +57,15 @@ abstract class ReplyController<R> extends CommonListController<R, ReplyInfo> {
}
@override
bool customHandleResponse(bool isRefresh, Success response) {
MainListReply data = response.response;
bool customHandleResponse(bool isRefresh, Success<R> response) {
final data = response.response as MainListReply;
cursorNext = data.cursor.next;
paginationReply = data.paginationReply;
count.value = data.subjectControl.count.toInt();
if (isRefresh) {
subjectControl = data.subjectControl;
upMid ??= data.subjectControl.upMid;
hasUpTop = data.hasUpTop();
if (data.hasUpTop()) {
if (hasUpTop = data.hasUpTop()) {
data.replies.insert(0, data.upTop);
}
if (subjectControl?.title == ReplySortType.select.title) {