From 163b8a3013652c661eeb25e32a45b139e4e0ad25 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 17 Oct 2024 00:36:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AF=84=E8=AE=BA=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/video/reply/content.dart | 17 ++- .../detail/reply/widgets/reply_item.dart | 115 +++++++++++++----- 2 files changed, 98 insertions(+), 34 deletions(-) diff --git a/lib/models/video/reply/content.dart b/lib/models/video/reply/content.dart index d62a4bca..3a5f90ab 100644 --- a/lib/models/video/reply/content.dart +++ b/lib/models/video/reply/content.dart @@ -1,6 +1,7 @@ class ReplyContent { ReplyContent({ this.message, + this.message2, this.atNameToMid, // @的用户的mid null this.members, // 被@的用户List 如果有的话 [] this.emote, // 表情包 如果有的话 null @@ -13,6 +14,7 @@ class ReplyContent { }); String? message; + String? message2; Map? atNameToMid; List? members; Map? emote; @@ -24,10 +26,17 @@ class ReplyContent { Map? topicsMeta; ReplyContent.fromJson(Map json) { - message = json['message'] + message = message2 = json['message'] .replaceAll('>', '>') .replaceAll('"', '"') - .replaceAll(''', "'"); + .replaceAll(''', "'") + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll(''', "'") + .replaceAll(' ', ' '); + atNameToMid = json['at_name_to_mid'] ?? {}; members = json['members'] != null ? json['members'] @@ -39,8 +48,8 @@ class ReplyContent { pictures = json['pictures'] ?? []; vote = json['vote'] ?? {}; richText = json['rich_text'] ?? {}; - // 不包含@ 笔记 图片的时候,文字可折叠 - isText = atNameToMid!.isEmpty && vote!.isEmpty && pictures!.isEmpty; + // 不包含@ 笔记的时候,文字可折叠 + isText = atNameToMid!.isEmpty && vote!.isEmpty; topicsMeta = json['topics_meta'] ?? {}; } } diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index 18242fea..52605121 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -238,28 +238,53 @@ class ReplyItem extends StatelessWidget { // title Container( margin: const EdgeInsets.only(top: 10, left: 45, right: 6, bottom: 4), - child: Text.rich( - style: const TextStyle(height: 1.75), - maxLines: - replyItem!.content!.isText! && replyLevel == '1' ? 3 : 999, - overflow: TextOverflow.ellipsis, - TextSpan( - children: [ - if (replyItem!.isTop!) - const WidgetSpan( - alignment: PlaceholderAlignment.top, - child: PBadge( - text: 'TOP', - size: 'small', - stack: 'normal', - type: 'line', - fs: 9, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints boxConstraints) { + String text = replyItem?.content?.message ?? ''; + bool didExceedMaxLines = false; + final double maxWidth = boxConstraints.maxWidth; + TextPainter? textPainter; + final int maxLines = + replyItem!.content!.isText! && replyLevel == '1' ? 6 : 999; + try { + textPainter = TextPainter( + text: TextSpan(text: text), + maxLines: maxLines, + textDirection: Directionality.of(context), + ); + textPainter.layout(maxWidth: maxWidth); + didExceedMaxLines = textPainter.didExceedMaxLines; + } catch (e) { + debugPrint('Error while measuring text: $e'); + didExceedMaxLines = false; + } + return Text.rich( + style: const TextStyle(height: 1.75), + TextSpan( + children: [ + if (replyItem!.isTop!) + const WidgetSpan( + alignment: PlaceholderAlignment.top, + child: PBadge( + text: 'TOP', + size: 'small', + stack: 'normal', + type: 'line', + fs: 9, + ), ), + buildContent( + context, + replyItem!, + replyReply, + null, + didExceedMaxLines, + textPainter, ), - buildContent(context, replyItem!, replyReply, null), - ], - ), - ), + ], + ), + ); + }), ), // 操作区域 bottonAction(context, replyItem!.replyControl, replySave), @@ -465,8 +490,8 @@ class ReplyItemRow extends StatelessWidget { fs: 9, ), ), - buildContent( - context, replies![i], replyReply, replyItem), + buildContent(context, replies![i], replyReply, + replyItem, false, null), ], ), ), @@ -508,7 +533,13 @@ class ReplyItemRow extends StatelessWidget { } InlineSpan buildContent( - BuildContext context, replyItem, replyReply, fReplyItem) { + BuildContext context, + replyItem, + replyReply, + fReplyItem, + bool didExceedMaxLines, + TextPainter? textPainter, +) { final String routePath = Get.currentRoute; bool isVideoPage = routePath.startsWith('/video'); ColorScheme colorScheme = Theme.of(context).colorScheme; @@ -519,6 +550,25 @@ InlineSpan buildContent( final content = replyItem.content; final List spanChilds = []; + if (didExceedMaxLines && content.message != '') { + final textSize = textPainter!.size; + var position = textPainter.getPositionForOffset( + Offset( + textSize.width, + textSize.height, + ), + ); + final endOffset = textPainter.getOffsetBefore(position.offset); + + if (endOffset != null && endOffset > 0) { + content.message = content.message.substring(0, endOffset); + } else { + content.message = content.message.substring(0, position.offset); + } + } else { + content.message = content.message2; + } + // 投票 if (content.vote.isNotEmpty) { content.message.splitMapJoin(RegExp(r"\{vote:.*?\}"), @@ -547,13 +597,6 @@ InlineSpan buildContent( }); } content.message = content.message.replaceAll(RegExp(r"\{vote:.*?\}"), ' '); - content.message = content.message - .replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('"', '"') - .replaceAll(''', "'") - .replaceAll(' ', ' '); // 构建正则表达式 final List specialTokens = [ ...content.emote.keys, @@ -874,6 +917,18 @@ InlineSpan buildContent( } } } + + if (didExceedMaxLines) { + spanChilds.add( + TextSpan( + text: '\n查看更多', + style: TextStyle( + color: colorScheme.primary, + ), + ), + ); + } + // 图片渲染 if (content.pictures.isNotEmpty) { final List picList = [];