mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: reply message
This commit is contained in:
@@ -246,38 +246,70 @@ class ReplyItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// title
|
// title
|
||||||
Container(
|
Padding(
|
||||||
margin: const EdgeInsets.only(top: 10, left: 45, right: 6, bottom: 4),
|
padding:
|
||||||
child: Semantics(
|
const EdgeInsets.only(top: 10, left: 45, right: 6, bottom: 4),
|
||||||
label: replyItem?.content?.message ?? "",
|
child: LayoutBuilder(
|
||||||
// excludeSemantics: true,
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
child: Text.rich(
|
String text = replyItem?.content?.message ?? '';
|
||||||
style: TextStyle(
|
var textPainter = TextPainter(
|
||||||
height: 1.75,
|
text: TextSpan(text: text),
|
||||||
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize),
|
|
||||||
maxLines:
|
maxLines:
|
||||||
replyItem!.content!.isText! && replyLevel == '1' ? 6 : 999,
|
replyItem!.content!.isText! && replyLevel == '1' ? 6 : 999,
|
||||||
overflow: TextOverflow.ellipsis,
|
textDirection: Directionality.of(context),
|
||||||
TextSpan(
|
)..layout(maxWidth: constraints.maxWidth);
|
||||||
children: [
|
bool didExceedMaxLines = textPainter.didExceedMaxLines;
|
||||||
if (replyItem!.isTop!) ...[
|
return Column(
|
||||||
const WidgetSpan(
|
mainAxisSize: MainAxisSize.min,
|
||||||
alignment: PlaceholderAlignment.top,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: PBadge(
|
children: [
|
||||||
text: 'TOP',
|
Semantics(
|
||||||
size: 'small',
|
label: text,
|
||||||
stack: 'normal',
|
child: Text.rich(
|
||||||
type: 'line',
|
style: TextStyle(
|
||||||
fs: 9,
|
height: 1.75,
|
||||||
semanticsLabel: '置顶',
|
fontSize: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium!
|
||||||
|
.fontSize),
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
if (replyItem!.isTop!) ...[
|
||||||
|
const WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.top,
|
||||||
|
child: PBadge(
|
||||||
|
text: 'TOP',
|
||||||
|
size: 'small',
|
||||||
|
stack: 'normal',
|
||||||
|
type: 'line',
|
||||||
|
fs: 9,
|
||||||
|
semanticsLabel: '置顶',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
],
|
||||||
|
buildContent(
|
||||||
|
context,
|
||||||
|
replyItem!,
|
||||||
|
replyReply,
|
||||||
|
null,
|
||||||
|
textPainter,
|
||||||
|
didExceedMaxLines,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
)),
|
||||||
|
if (didExceedMaxLines)
|
||||||
|
Text(
|
||||||
|
'查看更多',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
),
|
),
|
||||||
const TextSpan(text: ' '),
|
),
|
||||||
],
|
],
|
||||||
buildContent(context, replyItem!, replyReply, null),
|
);
|
||||||
],
|
},
|
||||||
),
|
),
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
// 操作区域
|
// 操作区域
|
||||||
buttonAction(context, replyItem!.replyControl),
|
buttonAction(context, replyItem!.replyControl),
|
||||||
@@ -425,73 +457,76 @@ 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:
|
label:
|
||||||
'${replies![i].member!.uname} ${replies![i].content!.message}',
|
'${replies![i].member!.uname} ${replies![i].content!.message}',
|
||||||
excludeSemantics: true,
|
excludeSemantics: true,
|
||||||
child: Text.rich(
|
child: Text.rich(
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context)
|
fontSize: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium!
|
.bodyMedium!
|
||||||
.fontSize,
|
.fontSize,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface
|
.onSurface
|
||||||
.withOpacity(0.85),
|
.withOpacity(0.85),
|
||||||
height: 1.6),
|
height: 1.6),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
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
|
||||||
.primary
|
.primary
|
||||||
.withOpacity(0.85),
|
.withOpacity(0.85),
|
||||||
),
|
|
||||||
recognizer: TapGestureRecognizer()
|
|
||||||
..onTap = () {
|
|
||||||
feedBack();
|
|
||||||
final String heroTag = Utils.makeHeroTag(
|
|
||||||
replies![i].member!.mid);
|
|
||||||
Get.toNamed(
|
|
||||||
'/member?mid=${replies![i].member!.mid}',
|
|
||||||
arguments: {
|
|
||||||
'face': replies![i].member!.avatar,
|
|
||||||
'heroTag': heroTag
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
if (replies![i].isUp!) ...[
|
recognizer: TapGestureRecognizer()
|
||||||
const TextSpan(text: ' '),
|
..onTap = () {
|
||||||
const WidgetSpan(
|
feedBack();
|
||||||
alignment: PlaceholderAlignment.top,
|
final String heroTag = Utils.makeHeroTag(
|
||||||
child: PBadge(
|
replies![i].member!.mid);
|
||||||
text: 'UP',
|
Get.toNamed(
|
||||||
size: 'small',
|
'/member?mid=${replies![i].member!.mid}',
|
||||||
stack: 'normal',
|
arguments: {
|
||||||
fs: 9,
|
'face': replies![i].member!.avatar,
|
||||||
),
|
'heroTag': heroTag
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (replies![i].isUp!) ...[
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
const WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.top,
|
||||||
|
child: PBadge(
|
||||||
|
text: 'UP',
|
||||||
|
size: 'small',
|
||||||
|
stack: 'normal',
|
||||||
|
fs: 9,
|
||||||
),
|
),
|
||||||
const TextSpan(text: ' '),
|
|
||||||
],
|
|
||||||
TextSpan(
|
|
||||||
text: replies![i].root == replies![i].parent
|
|
||||||
? ': '
|
|
||||||
: replies![i].isUp!
|
|
||||||
? ''
|
|
||||||
: ' '),
|
|
||||||
buildContent(
|
|
||||||
context,
|
|
||||||
replies![i],
|
|
||||||
replyReply,
|
|
||||||
replyItem,
|
|
||||||
),
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
],
|
],
|
||||||
),
|
TextSpan(
|
||||||
)),
|
text: replies![i].root == replies![i].parent
|
||||||
|
? ': '
|
||||||
|
: replies![i].isUp!
|
||||||
|
? ''
|
||||||
|
: ' '),
|
||||||
|
buildContent(
|
||||||
|
context,
|
||||||
|
replies![i],
|
||||||
|
replyReply,
|
||||||
|
replyItem,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -539,7 +574,13 @@ class ReplyItemRow extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InlineSpan buildContent(
|
InlineSpan buildContent(
|
||||||
BuildContext context, replyItem, replyReply, fReplyItem) {
|
BuildContext context,
|
||||||
|
replyItem,
|
||||||
|
replyReply,
|
||||||
|
fReplyItem,
|
||||||
|
textPainter,
|
||||||
|
didExceedMaxLines,
|
||||||
|
) {
|
||||||
final String routePath = Get.currentRoute;
|
final String routePath = Get.currentRoute;
|
||||||
bool isVideoPage = routePath.startsWith('/video');
|
bool isVideoPage = routePath.startsWith('/video');
|
||||||
|
|
||||||
@@ -547,12 +588,24 @@ InlineSpan buildContent(
|
|||||||
// replyReply 查看二楼回复(回复详情)回调
|
// replyReply 查看二楼回复(回复详情)回调
|
||||||
// fReplyItem 父级回复内容,用作二楼回复(回复详情)展示
|
// fReplyItem 父级回复内容,用作二楼回复(回复详情)展示
|
||||||
final content = replyItem.content;
|
final content = replyItem.content;
|
||||||
|
String message = content.message ?? '';
|
||||||
final List<InlineSpan> spanChildren = <InlineSpan>[];
|
final List<InlineSpan> spanChildren = <InlineSpan>[];
|
||||||
|
|
||||||
|
if (didExceedMaxLines == true) {
|
||||||
|
final textSize = textPainter.size;
|
||||||
|
var position = textPainter.getPositionForOffset(
|
||||||
|
Offset(
|
||||||
|
textSize.width,
|
||||||
|
textSize.height,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final endOffset = textPainter.getOffsetBefore(position.offset);
|
||||||
|
message = message.substring(0, endOffset);
|
||||||
|
}
|
||||||
|
|
||||||
// 投票
|
// 投票
|
||||||
if (content.vote.isNotEmpty) {
|
if (content.vote.isNotEmpty) {
|
||||||
content.message.splitMapJoin(RegExp(r"\{vote:\d+?\}"),
|
message.splitMapJoin(RegExp(r"\{vote:\d+?\}"), onMatch: (Match match) {
|
||||||
onMatch: (Match match) {
|
|
||||||
// String matchStr = match[0]!;
|
// String matchStr = match[0]!;
|
||||||
spanChildren.add(
|
spanChildren.add(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
@@ -575,9 +628,9 @@ InlineSpan buildContent(
|
|||||||
}, onNonMatch: (String str) {
|
}, onNonMatch: (String str) {
|
||||||
return str;
|
return str;
|
||||||
});
|
});
|
||||||
content.message = content.message.replaceAll(RegExp(r"\{vote:\d+?\}"), "");
|
message = message.replaceAll(RegExp(r"\{vote:\d+?\}"), "");
|
||||||
}
|
}
|
||||||
content.message = content.message
|
message = message
|
||||||
.replaceAll('&', '&')
|
.replaceAll('&', '&')
|
||||||
.replaceAll('<', '<')
|
.replaceAll('<', '<')
|
||||||
.replaceAll('>', '>')
|
.replaceAll('>', '>')
|
||||||
@@ -618,7 +671,7 @@ InlineSpan buildContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 分割文本并处理每个部分
|
// 分割文本并处理每个部分
|
||||||
content.message.splitMapJoin(
|
message.splitMapJoin(
|
||||||
pattern,
|
pattern,
|
||||||
onMatch: (Match match) {
|
onMatch: (Match match) {
|
||||||
String matchStr = match[0]!;
|
String matchStr = match[0]!;
|
||||||
@@ -835,7 +888,7 @@ InlineSpan buildContent(
|
|||||||
if (content.jumpUrl.keys.isNotEmpty) {
|
if (content.jumpUrl.keys.isNotEmpty) {
|
||||||
List<String> unmatchedItems = content.jumpUrl.keys
|
List<String> unmatchedItems = content.jumpUrl.keys
|
||||||
.toList()
|
.toList()
|
||||||
.where((item) => !content.message.contains(item))
|
.where((item) => !message.contains(item))
|
||||||
.toList();
|
.toList();
|
||||||
if (unmatchedItems.isNotEmpty) {
|
if (unmatchedItems.isNotEmpty) {
|
||||||
for (int i = 0; i < unmatchedItems.length; i++) {
|
for (int i = 0; i < unmatchedItems.length; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user