mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-08 02:00:13 +08:00
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -566,9 +566,7 @@ class _DynamicDetailPageState
|
||||
color: theme.colorScheme.surface,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
color: theme.colorScheme.outline.withValues(
|
||||
alpha: 0.08,
|
||||
),
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.08),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -5,10 +5,12 @@ import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_type.dart';
|
||||
import 'package:PiliPlus/pages/common/reply_controller.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/reply/vote/reply_vote_mixin.dart';
|
||||
import 'package:PiliPlus/utils/id_utils.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class VideoReplyController extends ReplyController<MainListReply> {
|
||||
class VideoReplyController extends ReplyController<MainListReply>
|
||||
with ReplyVoteMixin {
|
||||
VideoReplyController({
|
||||
required this.aid,
|
||||
required this.videoType,
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/pages/common/fab_mixin.dart';
|
||||
import 'package:PiliPlus/pages/video/reply/controller.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/feed_back.dart';
|
||||
@@ -125,9 +126,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
}),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => _buildBody(_videoReplyController.loadingState.value),
|
||||
),
|
||||
Obx(() => _buildBody(_videoReplyController.loadingState.value)),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
@@ -170,62 +169,75 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<ReplyInfo>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => SliverList.builder(
|
||||
itemBuilder: (context, index) => const VideoReplySkeleton(),
|
||||
itemCount: 5,
|
||||
),
|
||||
Success(:final response) =>
|
||||
response != null && response.isNotEmpty
|
||||
? SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
if (index == response.length) {
|
||||
_videoReplyController.onLoadMore();
|
||||
return Container(
|
||||
height: 125,
|
||||
alignment: .center,
|
||||
margin: .only(bottom: bottom),
|
||||
child: Text(
|
||||
_videoReplyController.isEnd ? '没有更多了' : '加载中...',
|
||||
textAlign: .center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return ReplyItemGrpc(
|
||||
replyItem: response[index],
|
||||
replyLevel: widget.replyLevel,
|
||||
replyReply: replyReply,
|
||||
onReply: _videoReplyController.onReply,
|
||||
onDelete: (item, subIndex) =>
|
||||
_videoReplyController.onRemove(index, item, subIndex),
|
||||
upMid: _videoReplyController.upMid,
|
||||
getTag: () => heroTag,
|
||||
onCheckReply: (item) => _videoReplyController
|
||||
.onCheckReply(item, isManual: true),
|
||||
onToggleTop: (item) => _videoReplyController.onToggleTop(
|
||||
item,
|
||||
index,
|
||||
_videoReplyController.aid,
|
||||
_videoReplyController.videoType.replyType,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
itemCount: response.length + 1,
|
||||
)
|
||||
: HttpError(
|
||||
errMsg: '还没有评论',
|
||||
onReload: _videoReplyController.onReload,
|
||||
),
|
||||
Error(:final errMsg) => HttpError(
|
||||
errMsg: errMsg,
|
||||
onReload: _videoReplyController.onReload,
|
||||
),
|
||||
};
|
||||
switch (loadingState) {
|
||||
case Loading():
|
||||
return SliverList.builder(
|
||||
itemBuilder: (context, index) => const VideoReplySkeleton(),
|
||||
itemCount: 5,
|
||||
);
|
||||
case Success(:final response):
|
||||
if (response != null && response.isNotEmpty) {
|
||||
var count = response.length + 1;
|
||||
final voteCard = _videoReplyController.voteCard;
|
||||
final hasVote = voteCard != null;
|
||||
if (hasVote) {
|
||||
count++;
|
||||
}
|
||||
return SliverList.builder(
|
||||
itemBuilder: (context, index) {
|
||||
if (hasVote) {
|
||||
if (index == 0) {
|
||||
return buildVoteCard(context, colorScheme, voteCard);
|
||||
} else {
|
||||
index--;
|
||||
}
|
||||
}
|
||||
if (index == response.length) {
|
||||
_videoReplyController.onLoadMore();
|
||||
return Container(
|
||||
height: 125,
|
||||
alignment: .center,
|
||||
margin: .only(bottom: bottom),
|
||||
child: Text(
|
||||
_videoReplyController.isEnd ? '没有更多了' : '加载中...',
|
||||
textAlign: .center,
|
||||
style: TextStyle(fontSize: 12, color: colorScheme.outline),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return ReplyItemGrpc(
|
||||
replyItem: response[index],
|
||||
replyLevel: widget.replyLevel,
|
||||
replyReply: replyReply,
|
||||
onReply: _videoReplyController.onReply,
|
||||
onDelete: (item, subIndex) =>
|
||||
_videoReplyController.onRemove(index, item, subIndex),
|
||||
upMid: _videoReplyController.upMid,
|
||||
getTag: () => heroTag,
|
||||
onCheckReply: (item) =>
|
||||
_videoReplyController.onCheckReply(item, isManual: true),
|
||||
onToggleTop: (item) => _videoReplyController.onToggleTop(
|
||||
item,
|
||||
index,
|
||||
_videoReplyController.aid,
|
||||
_videoReplyController.videoType.replyType,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
itemCount: count,
|
||||
);
|
||||
}
|
||||
return HttpError(
|
||||
errMsg: '还没有评论',
|
||||
onReload: _videoReplyController.onReload,
|
||||
);
|
||||
case Error(:final errMsg):
|
||||
return HttpError(
|
||||
errMsg: errMsg,
|
||||
onReload: _videoReplyController.onReload,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 展示二级回复
|
||||
|
||||
49
lib/pages/video/reply/vote/reply_vote_item.dart
Normal file
49
lib/pages/video/reply/vote/reply_vote_item.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
||||
show VoteCard;
|
||||
import 'package:PiliPlus/pages/dynamics/widgets/vote.dart';
|
||||
import 'package:PiliPlus/utils/num_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
Widget buildVoteCard(
|
||||
BuildContext context,
|
||||
ColorScheme colorScheme,
|
||||
VoteCard voteCard,
|
||||
) {
|
||||
return InkWell(
|
||||
onTap: () => showVoteDialog(context, voteCard.voteId.toInt()),
|
||||
child: Padding(
|
||||
padding: const .symmetric(horizontal: 12, vertical: 6),
|
||||
child: Row(
|
||||
spacing: 10,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.onInverseSurface,
|
||||
borderRadius: const .all(.circular(8)),
|
||||
),
|
||||
width: 60,
|
||||
height: 42,
|
||||
child: Icon(
|
||||
Icons.bar_chart_rounded,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
Text(voteCard.title, maxLines: 1, overflow: .ellipsis),
|
||||
Text(
|
||||
'${NumUtils.numFormat(voteCard.count.toInt())}人参与',
|
||||
maxLines: 1,
|
||||
overflow: .ellipsis,
|
||||
style: TextStyle(fontSize: 13, color: colorScheme.outline),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
19
lib/pages/video/reply/vote/reply_vote_mixin.dart
Normal file
19
lib/pages/video/reply/vote/reply_vote_mixin.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
||||
show MainListReply, VoteCard, ReplyInfo;
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
|
||||
mixin ReplyVoteMixin on CommonListController<MainListReply, ReplyInfo> {
|
||||
VoteCard? voteCard;
|
||||
|
||||
@override
|
||||
bool customHandleResponse(bool isRefresh, Success<MainListReply> response) {
|
||||
if (isRefresh) {
|
||||
final res = response.response;
|
||||
if (res.hasVoteCard()) {
|
||||
voteCard = res.voteCard;
|
||||
}
|
||||
}
|
||||
return super.customHandleResponse(isRefresh, response);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/image_grid/image_grid_view.dart';
|
||||
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
|
||||
import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
||||
show ReplyInfo, ReplyControl, Content, Url;
|
||||
show ReplyInfo, ReplyControl, Content, Url, ReplyControl_VoteOption;
|
||||
import 'package:PiliPlus/grpc/reply.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/reply.dart';
|
||||
@@ -92,7 +92,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final colorScheme = ColorScheme.of(context);
|
||||
|
||||
void showMore() => showModalBottomSheet(
|
||||
context: context,
|
||||
@@ -113,7 +113,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
Widget child = Padding(
|
||||
padding: const .fromLTRB(12, 14, 8, 5),
|
||||
child: _buildContent(context, theme),
|
||||
child: _buildContent(context, colorScheme),
|
||||
);
|
||||
if (needDivider) {
|
||||
child = Column(
|
||||
@@ -124,7 +124,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
indent: 55,
|
||||
endIndent: 15,
|
||||
height: 0.3,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.08),
|
||||
color: colorScheme.outline.withValues(alpha: 0.08),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -140,7 +140,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader(BuildContext context, ThemeData theme) {
|
||||
Widget _buildHeader(BuildContext context, ColorScheme colorScheme) {
|
||||
final member = replyItem.member;
|
||||
Widget header = GestureDetector(
|
||||
onTap: () {
|
||||
@@ -178,8 +178,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
overflow: .ellipsis,
|
||||
style: TextStyle(
|
||||
color: (member.vipStatus > 0 && member.vipType == 2)
|
||||
? theme.colorScheme.vipColor
|
||||
: theme.colorScheme.outline,
|
||||
? colorScheme.vipColor
|
||||
: colorScheme.outline,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
@@ -227,16 +227,16 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
replyItem.ctime.toInt(),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: 11,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
),
|
||||
if (replyItem.replyControl.hasLocation())
|
||||
Text(
|
||||
' • ${replyItem.replyControl.location}',
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: 11,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -293,23 +293,56 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
return header;
|
||||
}
|
||||
|
||||
Widget _buildContent(BuildContext context, ThemeData theme) {
|
||||
Widget _buildVoteOption(
|
||||
ColorScheme colorScheme,
|
||||
ReplyControl_VoteOption voteOption,
|
||||
) {
|
||||
return Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
switch (voteOption.labelKind) {
|
||||
.RED => TextSpan(
|
||||
text: '红队 ',
|
||||
style: TextStyle(color: colorScheme.vipColor),
|
||||
),
|
||||
.BLUE => TextSpan(
|
||||
text: '蓝队 ',
|
||||
style: TextStyle(color: colorScheme.blue),
|
||||
),
|
||||
_ => TextSpan(
|
||||
text: '投票 ',
|
||||
style: TextStyle(color: colorScheme.outline),
|
||||
),
|
||||
},
|
||||
TextSpan(text: voteOption.desc),
|
||||
],
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildContent(BuildContext context, ColorScheme colorScheme) {
|
||||
final replyControl = replyItem.replyControl;
|
||||
final padding = EdgeInsets.only(left: replyLevel == 0 ? 6 : 45, right: 6);
|
||||
return Column(
|
||||
mainAxisSize: .min,
|
||||
crossAxisAlignment: .start,
|
||||
children: [
|
||||
_buildHeader(context, theme),
|
||||
_buildHeader(context, colorScheme),
|
||||
const SizedBox(height: 10),
|
||||
if (replyControl.hasVoteOption())
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: _buildVoteOption(colorScheme, replyControl.voteOption),
|
||||
),
|
||||
Padding(
|
||||
padding: padding,
|
||||
child: custom_text.Text.rich(
|
||||
primary: theme.colorScheme.primary,
|
||||
style: TextStyle(
|
||||
height: 1.75,
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
),
|
||||
primary: colorScheme.primary,
|
||||
style: const TextStyle(height: 1.75, fontSize: 14),
|
||||
maxLines: replyLevel == 1 ? replyLengthLimit : null,
|
||||
TextSpan(
|
||||
children: [
|
||||
@@ -329,7 +362,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
],
|
||||
_buildMessage(
|
||||
context,
|
||||
theme,
|
||||
colorScheme,
|
||||
replyControl.showTranslation
|
||||
? replyItem.translatedContent
|
||||
: replyItem.content,
|
||||
@@ -359,12 +392,12 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
],
|
||||
if (replyLevel != 0) ...[
|
||||
const SizedBox(height: 4),
|
||||
buttonAction(context, theme, replyControl),
|
||||
buttonAction(context, colorScheme, replyControl),
|
||||
],
|
||||
if (replyLevel == 1 && replyItem.count > Int64.ZERO) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5, bottom: 12),
|
||||
child: replyItemRow(context, theme, replyItem.replies),
|
||||
child: replyItemRow(context, colorScheme, replyItem.replies),
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -373,15 +406,15 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
Widget _buildTranslateBtn(
|
||||
BuildContext context,
|
||||
ThemeData theme,
|
||||
ColorScheme colorScheme,
|
||||
ReplyControl replyControl,
|
||||
TextStyle textStyle,
|
||||
ButtonStyle buttonStyle,
|
||||
) {
|
||||
late bool isProcessing = false;
|
||||
final color = replyControl.showTranslation
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.outline.withValues(alpha: 0.8);
|
||||
? colorScheme.primary
|
||||
: colorScheme.outline.withValues(alpha: 0.8);
|
||||
return SizedBox(
|
||||
height: 32,
|
||||
child: TextButton(
|
||||
@@ -439,14 +472,14 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
Widget buttonAction(
|
||||
BuildContext context,
|
||||
ThemeData theme,
|
||||
ColorScheme colorScheme,
|
||||
ReplyControl replyControl,
|
||||
) {
|
||||
final textStyle = TextStyle(
|
||||
height: 1,
|
||||
fontSize: 12,
|
||||
fontWeight: .normal,
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
color: colorScheme.outline,
|
||||
);
|
||||
const buttonStyle = ButtonStyle(
|
||||
visualDensity: .compact,
|
||||
@@ -492,7 +525,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.reply,
|
||||
size: 18,
|
||||
color: theme.colorScheme.outline.withValues(alpha: 0.8),
|
||||
color: colorScheme.outline.withValues(alpha: 0.8),
|
||||
),
|
||||
Text('回复', style: textStyle),
|
||||
],
|
||||
@@ -504,7 +537,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
.TRANSLATION_SWITCH_SHOW_TRANSLATION) ...[
|
||||
_buildTranslateBtn(
|
||||
context,
|
||||
theme,
|
||||
colorScheme,
|
||||
replyControl,
|
||||
textStyle,
|
||||
buttonStyle,
|
||||
@@ -515,7 +548,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
dialogBtn != null
|
||||
? replyControl.cardLabels.first.textContent
|
||||
: replyControl.cardLabels.map((e) => e.textContent).join(' '),
|
||||
style: textStyle.copyWith(color: theme.colorScheme.secondary),
|
||||
style: textStyle.copyWith(color: colorScheme.secondary),
|
||||
),
|
||||
const SizedBox(width: 2),
|
||||
],
|
||||
@@ -529,7 +562,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
Widget replyItemRow(
|
||||
BuildContext context,
|
||||
ThemeData theme,
|
||||
ColorScheme colorScheme,
|
||||
List<ReplyInfo> replies,
|
||||
) {
|
||||
final extraRow = replies.length < replyItem.count.toInt();
|
||||
@@ -537,7 +570,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 42, right: 4),
|
||||
child: Material(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
color: colorScheme.onInverseSurface,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
animationDuration: Duration.zero,
|
||||
@@ -584,11 +617,9 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
padding: padding,
|
||||
child: Text.rich(
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
color: theme.colorScheme.onSurface.withValues(
|
||||
alpha: 0.85,
|
||||
),
|
||||
height: 1.6,
|
||||
fontSize: 14,
|
||||
color: colorScheme.onSurface.withValues(alpha: 0.85),
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
@@ -596,9 +627,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
children: [
|
||||
TextSpan(
|
||||
text: childReply.member.name,
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
style: TextStyle(color: colorScheme.primary),
|
||||
recognizer: NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () {
|
||||
feedBack();
|
||||
@@ -630,7 +659,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
),
|
||||
_buildMessage(
|
||||
context,
|
||||
theme,
|
||||
colorScheme,
|
||||
childReply.content,
|
||||
childReply.replyControl,
|
||||
),
|
||||
@@ -649,15 +678,13 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
: const EdgeInsets.fromLTRB(8, 5, 8, 8),
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
),
|
||||
style: const TextStyle(fontSize: 12),
|
||||
children: [
|
||||
if (replyItem.replyControl.upReply)
|
||||
TextSpan(
|
||||
text: 'UP主等人 ',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onSurface.withValues(
|
||||
color: colorScheme.onSurface.withValues(
|
||||
alpha: 0.85,
|
||||
),
|
||||
),
|
||||
@@ -665,7 +692,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: '共${replyItem.count}条回复',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -681,7 +708,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
InlineSpan _buildMessage(
|
||||
BuildContext context,
|
||||
ThemeData theme,
|
||||
ColorScheme colorScheme,
|
||||
Content content,
|
||||
ReplyControl replyControl,
|
||||
) {
|
||||
@@ -727,16 +754,14 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
child: CachedNetworkImage(
|
||||
height: 19,
|
||||
memCacheHeight: 19.cacheSize(context),
|
||||
color: theme.colorScheme.primary,
|
||||
color: colorScheme.primary,
|
||||
imageUrl: ImageUtils.thumbnailUrl(url.prefixIcon),
|
||||
placeholder: (_, _) => const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: isCv ? '[笔记] ' : url.title,
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
style: TextStyle(color: colorScheme.primary),
|
||||
recognizer: NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () {
|
||||
if (url.appUrlSchema.isEmpty) {
|
||||
@@ -815,7 +840,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
style: TextStyle(color: colorScheme.primary),
|
||||
recognizer: NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () =>
|
||||
Get.toNamed('/member?mid=${content.atNameToMid[name]}'),
|
||||
@@ -825,7 +850,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: '投票: ${content.vote.title}',
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
style: TextStyle(color: colorScheme.primary),
|
||||
recognizer: NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () =>
|
||||
showVoteDialog(context, content.vote.id.toInt()),
|
||||
@@ -847,9 +872,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: isValid ? ' $matchStr ' : matchStr,
|
||||
style: isValid
|
||||
? TextStyle(color: theme.colorScheme.primary)
|
||||
: null,
|
||||
style: isValid ? TextStyle(color: colorScheme.primary) : null,
|
||||
recognizer: isValid
|
||||
? (NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -881,7 +904,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
style: TextStyle(color: colorScheme.primary),
|
||||
recognizer: NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () {
|
||||
Get.toNamed(
|
||||
@@ -895,7 +918,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
style: TextStyle(color: colorScheme.primary),
|
||||
recognizer: NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () => PageUtils.handleWebview(matchStr),
|
||||
),
|
||||
@@ -929,7 +952,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
final hasClickUrl = content.richText.note.hasClickUrl();
|
||||
if (hasClickUrl || content.richText.opus.hasOpusId()) {
|
||||
color = theme.colorScheme.primary;
|
||||
color = colorScheme.primary;
|
||||
recognizer = NoDeadlineTapGestureRecognizer()
|
||||
..onTap = () => hasClickUrl
|
||||
? PiliScheme.routePushFromUrl(content.richText.note.clickUrl)
|
||||
@@ -941,7 +964,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
} else {
|
||||
color = theme.colorScheme.secondary;
|
||||
color = colorScheme.secondary;
|
||||
}
|
||||
spanChildren.insert(
|
||||
0,
|
||||
@@ -965,11 +988,12 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
late String message = item.content.message;
|
||||
final ownerMid = Int64(Accounts.main.mid);
|
||||
final theme = Theme.of(context);
|
||||
final errorColor = theme.colorScheme.error;
|
||||
final colorScheme = theme.colorScheme;
|
||||
final errorColor = colorScheme.error;
|
||||
final style = theme.textTheme.titleSmall!;
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
padding: .only(
|
||||
bottom: MediaQuery.viewPaddingOf(context).bottom + 20,
|
||||
),
|
||||
child: Column(
|
||||
@@ -985,7 +1009,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
width: 32,
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.outline,
|
||||
color: colorScheme.outline,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(3)),
|
||||
),
|
||||
),
|
||||
@@ -1007,7 +1031,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
},
|
||||
title: Text(
|
||||
'save to local',
|
||||
style: style.copyWith(color: theme.colorScheme.primary),
|
||||
style: style.copyWith(color: colorScheme.primary),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
@@ -1018,7 +1042,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
},
|
||||
title: Text(
|
||||
'remove from local',
|
||||
style: style.copyWith(color: theme.colorScheme.primary),
|
||||
style: style.copyWith(color: colorScheme.primary),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
@@ -1037,7 +1061,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
},
|
||||
title: Text(
|
||||
'save to local (x1000)',
|
||||
style: style.copyWith(color: theme.colorScheme.primary),
|
||||
style: style.copyWith(color: colorScheme.primary),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -1048,7 +1072,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
bool? isDelete = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = ColorScheme.of(context);
|
||||
return AlertDialog(
|
||||
title: const Text('删除评论'),
|
||||
content: Text.rich(
|
||||
@@ -1059,7 +1083,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: '@${item.member.name}',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.primary,
|
||||
color: colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const TextSpan(text: ':\n'),
|
||||
@@ -1074,7 +1098,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.outline,
|
||||
color: colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user