diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 14e569a58..e467820a9 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -45,4 +45,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.1 diff --git a/lib/common/widgets/network_img_layer.dart b/lib/common/widgets/network_img_layer.dart index e8249b808..ce98c9a95 100644 --- a/lib/common/widgets/network_img_layer.dart +++ b/lib/common/widgets/network_img_layer.dart @@ -36,6 +36,7 @@ class NetworkImgLayer extends StatelessWidget { imageUrl: src!, width: width ?? double.infinity, height: height ?? double.infinity, + alignment: Alignment.center, maxWidthDiskCache: ((cacheW ?? width!) * pr).toInt(), // maxHeightDiskCache: (cacheH ?? height!).toInt(), memCacheWidth: ((cacheW ?? width!) * pr).toInt(), diff --git a/lib/common/widgets/reply_item.dart b/lib/common/widgets/reply_item.dart deleted file mode 100644 index f7b65ff51..000000000 --- a/lib/common/widgets/reply_item.dart +++ /dev/null @@ -1,255 +0,0 @@ -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:pilipala/common/widgets/network_img_layer.dart'; -import 'package:pilipala/models/video/reply/item.dart'; -import 'package:pilipala/utils/utils.dart'; - -class ReplyItem extends StatelessWidget { - ReplyItem({super.key, this.replyItem, required this.isUp}); - ReplyItemModel? replyItem; - bool isUp = false; - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: () {}, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(12, 8, 8, 14), - child: content(context), - ), - Divider( - height: 1, - color: Theme.of(context).dividerColor.withOpacity(0.08), - ) - ], - ), - ); - } - - Widget lfAvtar(context) { - return Container( - margin: const EdgeInsets.only(top: 5), - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context).colorScheme.primary.withOpacity(0.03)), - ), - child: NetworkImgLayer( - src: replyItem!.member!.avatar, - width: 34, - height: 34, - type: 'avatar', - ), - ); - } - - Widget content(context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 头像、昵称 - Row( - // 两端对齐 - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - GestureDetector( - // onTap: () => - // Get.toNamed('/member/${reply.userName}', parameters: { - // 'memberAvatar': reply.avatar, - // 'heroTag': reply.userName + heroTag, - // }), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - lfAvtar(context), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - replyItem!.member!.uname!, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: Theme.of(context) - .textTheme - .titleSmall! - .copyWith( - color: isUp! - ? Theme.of(context).colorScheme.primary - : null, - ), - ), - const SizedBox(width: 6), - Image.asset( - 'assets/images/lv/lv${replyItem!.member!.level}.png', - height: 13, - ), - ], - ), - Text( - Utils.dateFormat(replyItem!.ctime), - style: Theme.of(context).textTheme.labelSmall!.copyWith( - color: Theme.of(context).colorScheme.outline), - ), - ], - ) - ], - ), - ), - // SizedBox( - // width: 35, - // height: 35, - // child: IconButton( - // padding: const EdgeInsets.all(2.0), - // icon: const Icon(Icons.more_horiz_outlined, size: 18.0), - // onPressed: () {}, - // ), - // ) - ], - ), - // title - Container( - margin: const EdgeInsets.only(top: 6, left: 45, right: 8), - child: SelectionArea( - child: Text( - replyItem!.content!.message!, - style: const TextStyle(height: 1.8), - ), - ), - ), - bottonAction(context), - // Text(replyItem!.replies!.length.toString()), - if (replyItem!.replies!.isNotEmpty) - ReplyItemRow( - replies: replyItem!.replies, - replyControl: replyItem!.replyControl, - ) - ], - ); - } - - // 感谢、回复、复制 - Widget bottonAction(context) { - var color = Theme.of(context).colorScheme.outline; - return Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - const SizedBox(width: 42), - SizedBox( - height: 35, - child: TextButton( - child: Row( - children: [ - Icon( - Icons.thumb_up_alt_outlined, - size: 16, - color: color, - ), - const SizedBox(width: 4), - Text( - replyItem!.like.toString(), - style: TextStyle( - color: color, - fontSize: - Theme.of(context).textTheme.labelSmall!.fontSize), - ), - ], - ), - onPressed: () {}, - ), - ), - const SizedBox(width: 5) - ], - ); - } -} - -class ReplyItemRow extends StatelessWidget { - ReplyItemRow({super.key, this.replies, this.replyControl}); - List? replies; - var replyControl; - - @override - Widget build(BuildContext context) { - bool isShow = replyControl.isShow; - int extraRow = replyControl != null && isShow ? 1 : 0; - return Container( - margin: const EdgeInsets.only(left: 45, right: 10), - padding: const EdgeInsets.only(top: 4, bottom: 4), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6), - ), - child: Material( - color: Theme.of(context).colorScheme.onInverseSurface.withOpacity(0.7), - borderRadius: BorderRadius.circular(6), - clipBehavior: Clip.hardEdge, - child: ListView.builder( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: replies!.length + extraRow, - itemBuilder: (context, index) { - if (extraRow == 1 && index == replies!.length) { - return ListTile( - onTap: () {}, - dense: true, - contentPadding: const EdgeInsets.only(left: 10, right: 6), - title: Text.rich( - TextSpan( - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - fontSize: - Theme.of(context).textTheme.titleSmall!.fontSize, - ), - children: [ - if (replyControl.upReply) const TextSpan(text: 'up回复了'), - if (replyControl.isUpTop) const TextSpan(text: 'up点赞了'), - TextSpan(text: replyControl.entryText) - ], - ), - ), - ); - } else { - return ListTile( - onTap: () {}, - dense: true, - contentPadding: const EdgeInsets.only(left: 10, right: 6), - title: Text.rich( - overflow: TextOverflow.ellipsis, - maxLines: 2, - TextSpan( - children: [ - TextSpan( - text: replies![index].member.uname + ':', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .titleSmall! - .fontSize, - color: Theme.of(context).colorScheme.primary, - ), - recognizer: TapGestureRecognizer() - ..onTap = () => {print('跳转至用户主页')}), - TextSpan( - text: replies![index].content.message, - style: TextStyle( - fontSize: - Theme.of(context).textTheme.titleSmall!.fontSize, - ), - ) - ], - ), - ), - ); - } - }, - ), - ), - ); - } -} diff --git a/lib/models/video/reply/content.dart b/lib/models/video/reply/content.dart index f924d3f21..83dbd556f 100644 --- a/lib/models/video/reply/content.dart +++ b/lib/models/video/reply/content.dart @@ -1,10 +1,11 @@ class ReplyContent { ReplyContent({ this.message, - this.atNameToMid, // @的用户的mid - this.memebers, // 被@的用户List 如果有的话 - this.emote, // 表情包 如果有的话 - this.jumpUrl, + this.atNameToMid, // @的用户的mid null + this.memebers, // 被@的用户List 如果有的话 [] + this.emote, // 表情包 如果有的话 null + this.jumpUrl, // {} + this.pictures, // {} }); String? message; @@ -12,12 +13,14 @@ class ReplyContent { List? memebers; Map? emote; Map? jumpUrl; + List? pictures; ReplyContent.fromJson(Map json) { message = json['message']; - atNameToMid = json['at_name_to_mid']; - memebers = json['memebers']; - emote = json['emote']; - jumpUrl = json['jumpUrl']; + atNameToMid = json['at_name_to_mid'] ?? {}; + memebers = json['memebers'] ?? []; + emote = json['emote'] ?? {}; + jumpUrl = json['jumpUrl'] ?? {}; + pictures = json['pictures'] ?? []; } } diff --git a/lib/models/video/reply/data.dart b/lib/models/video/reply/data.dart index b47ff656c..3b94a0081 100644 --- a/lib/models/video/reply/data.dart +++ b/lib/models/video/reply/data.dart @@ -15,18 +15,22 @@ class ReplyData { ReplyPage? page; ReplyConfig? config; - late List? replies; - late List? topReplies; + late List? replies; + late List? topReplies; ReplyUpper? upper; ReplyData.fromJson(Map json) { page = ReplyPage.fromJson(json['page']); config = ReplyConfig.fromJson(json['config']); - replies = - json['replies'].map((item) => ReplyItemModel.fromJson(item)).toList(); + replies = json['replies'] + .map( + (item) => ReplyItemModel.fromJson(item, json['upper']['mid'])) + .toList(); topReplies = json['top_replies'] != null ? json['top_replies'] - .map((item) => ReplyItemModel.fromJson(item)) + .map((item) => ReplyItemModel.fromJson( + item, json['upper']['mid'], + isTopStatus: true)) .toList() : []; upper = ReplyUpper.fromJson(json['upper']); diff --git a/lib/models/video/reply/item.dart b/lib/models/video/reply/item.dart index c012f73da..53b71b6e1 100644 --- a/lib/models/video/reply/item.dart +++ b/lib/models/video/reply/item.dart @@ -28,6 +28,8 @@ class ReplyItemModel { this.upAction, this.invisible, this.replyControl, + this.isUp, + this.isTop, }); int? rpid; @@ -55,8 +57,11 @@ class ReplyItemModel { UpAction? upAction; bool? invisible; ReplyControl? replyControl; + bool? isUp; + bool? isTop = false; - ReplyItemModel.fromJson(Map json) { + ReplyItemModel.fromJson(Map json, upperMid, + {isTopStatus = false}) { rpid = json['rpid']; oid = json['oid']; type = json['type']; @@ -78,7 +83,9 @@ class ReplyItemModel { member = ReplyMember.fromJson(json['member']); content = ReplyContent.fromJson(json['content']); replies = json['replies'] != null - ? json['replies'].map((item) => ReplyItemModel.fromJson(item)).toList() + ? json['replies'] + .map((item) => ReplyItemModel.fromJson(item, upperMid)) + .toList() : []; assist = json['assist']; upAction = UpAction.fromJson(json['up_action']); @@ -86,6 +93,8 @@ class ReplyItemModel { replyControl = json['reply_control'] == null ? null : ReplyControl.fromJson(json['reply_control']); + isUp = upperMid.toString() == json['member']['mid']; + isTop = isTopStatus; } } @@ -126,7 +135,7 @@ class ReplyControl { upReply = json['up_reply'] ?? false; isUpTop = json['is_up_top'] ?? false; upLike = json['up_like'] ?? false; - if (json['sub_reply_entry_text'] == null) { + if (json['sub_reply_entry_text'] != null) { final RegExp regex = RegExp(r"\d+"); final RegExpMatch match = regex.firstMatch( json['sub_reply_entry_text'] == null diff --git a/lib/models/video/reply/upper.dart b/lib/models/video/reply/upper.dart index 530513aaa..4bdb62aa0 100644 --- a/lib/models/video/reply/upper.dart +++ b/lib/models/video/reply/upper.dart @@ -12,7 +12,7 @@ class ReplyUpper { ReplyUpper.fromJson(Map json) { mid = json['mid']; top = json['top'] != null - ? ReplyItemModel.fromJson(json['top']) + ? ReplyItemModel.fromJson(json['top'], json['mid']) : ReplyItemModel(); } } diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index dd45ef113..67341100e 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -2,8 +2,9 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/skeleton/video_card_h.dart'; import 'package:pilipala/common/widgets/http_error.dart'; -import 'package:pilipala/common/widgets/reply_item.dart'; +import 'package:pilipala/models/video/reply/item.dart'; import 'controller.dart'; +import 'widgets/reply_item.dart'; class VideoReplyPanel extends StatefulWidget { const VideoReplyPanel({super.key}); @@ -28,8 +29,24 @@ class _VideoReplyPanelState extends State builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.data['status']) { - List replies = snapshot.data['data'].replies; - replies.addAll(snapshot.data['data'].topReplies); + List replies = snapshot.data['data'].replies; + // 添加置顶回复 + if (snapshot.data['data'].upper.top != null) { + bool flag = false; + for (var i = 0; + i < snapshot.data['data'].topReplies.length; + i++) { + if (snapshot.data['data'].topReplies[i].rpid == + snapshot.data['data'].upper.top.rpid) { + flag = true; + } + } + if (!flag) { + replies.insert(0, snapshot.data['data'].upper.top); + } + } + + replies.insertAll(0, snapshot.data['data'].topReplies); // 请求成功 return SliverList( delegate: SliverChildBuilderDelegate((context, index) { diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart new file mode 100644 index 000000000..184ced820 --- /dev/null +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -0,0 +1,448 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/models/video/reply/item.dart'; +import 'package:pilipala/utils/utils.dart'; + +class ReplyItem extends StatelessWidget { + ReplyItem({super.key, this.replyItem, required this.isUp}); + ReplyItemModel? replyItem; + bool isUp = false; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () {}, + child: Column( + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(12, 8, 8, 0), + child: content(context), + ), + Divider( + height: 1, + color: Theme.of(context).dividerColor.withOpacity(0.08), + ) + ], + ), + ); + } + + Widget lfAvtar(context) { + return Container( + margin: const EdgeInsets.only(top: 5), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context).colorScheme.primary.withOpacity(0.03)), + ), + child: NetworkImgLayer( + src: replyItem!.member!.avatar, + width: 30, + height: 30, + type: 'avatar', + ), + ); + } + + Widget content(context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 头像、昵称 + Row( + // 两端对齐 + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + GestureDetector( + // onTap: () => + // Get.toNamed('/member/${reply.userName}', parameters: { + // 'memberAvatar': reply.avatar, + // 'heroTag': reply.userName + heroTag, + // }), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + lfAvtar(context), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + replyItem!.member!.uname!, + style: Theme.of(context) + .textTheme + .titleSmall! + .copyWith( + color: replyItem!.isUp! + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, + ), + ), + const SizedBox(width: 6), + Image.asset( + 'assets/images/lv/lv${replyItem!.member!.level}.png', + height: 13, + ), + ], + ), + ], + ) + ], + ), + ), + ], + ), + // title + Container( + margin: const EdgeInsets.only(top: 0, left: 45, right: 6), + child: SelectableRegion( + magnifierConfiguration: const TextMagnifierConfiguration(), + focusNode: FocusNode(), + selectionControls: MaterialTextSelectionControls(), + child: Text.rich( + style: const TextStyle(height: 1.6), + TextSpan( + children: [ + buildContent(context, replyItem!.content!), + ], + ), + ), + ), + ), + // 操作区域 + bottonAction(context, replyItem!.replyControl), + if (replyItem!.replies!.isNotEmpty) ...[ + Padding( + padding: const EdgeInsets.only(top: 2, bottom: 12), + child: ReplyItemRow( + replies: replyItem!.replies, + replyControl: replyItem!.replyControl, + ), + ), + ], + ], + ); + } + + // 感谢、回复、复制 + Widget bottonAction(context, replyControl) { + var color = Theme.of(context).colorScheme.outline; + return Row( + children: [ + const SizedBox(width: 48), + Text( + Utils.dateFormat(replyItem!.ctime), + style: Theme.of(context) + .textTheme + .labelMedium! + .copyWith(color: Theme.of(context).colorScheme.outline), + ), + if (replyItem!.isTop!) ...[ + Text( + ' • 置顶', + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.primary, + ), + ), + ], + if (replyControl!.isUpTop!) ...[ + Text( + ' • 超赞', + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.primary, + ), + ), + // const SizedBox(width: 4), + ], + const Spacer(), + SizedBox( + height: 35, + child: TextButton( + child: Row( + children: [ + Icon( + Icons.thumb_up_alt_outlined, + size: 16, + color: color, + ), + const SizedBox(width: 4), + Text( + replyItem!.like.toString(), + style: TextStyle( + color: color, + fontSize: + Theme.of(context).textTheme.labelSmall!.fontSize), + ), + ], + ), + onPressed: () {}, + ), + ), + const SizedBox(width: 5) + ], + ); + } +} + +// ignore: must_be_immutable +class ReplyItemRow extends StatelessWidget { + ReplyItemRow({ + super.key, + this.replies, + this.replyControl, + }); + List? replies; + ReplyControl? replyControl; + + @override + Widget build(BuildContext context) { + bool isShow = replyControl!.isShow!; + int extraRow = replyControl != null && isShow ? 1 : 0; + return Container( + margin: const EdgeInsets.only(left: 42, right: 4, top: 0), + child: Material( + color: Theme.of(context).colorScheme.onInverseSurface.withOpacity(0.7), + borderRadius: BorderRadius.circular(6), + clipBehavior: Clip.hardEdge, + animationDuration: Duration.zero, + child: ListView.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: replies!.length + extraRow, + itemBuilder: (context, index) { + if (extraRow == 1 && index == replies!.length) { + // 有楼中楼回复,在最后显示 + return InkWell( + onTap: () {}, + child: Padding( + padding: + const EdgeInsets.symmetric(vertical: 8, horizontal: 8), + child: Text.rich( + TextSpan( + style: TextStyle( + fontSize: + Theme.of(context).textTheme.labelMedium!.fontSize, + ), + children: [ + if (replyControl!.upReply!) + const TextSpan(text: 'up主等人 '), + TextSpan( + text: replyControl!.entryText!, + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + ), + ) + ], + ), + ), + ), + ); + } else { + return InkWell( + onTap: () {}, + child: Padding( + padding: EdgeInsets.fromLTRB(8, index == 0 ? 8 : 4, 8, 4), + child: Text.rich( + overflow: TextOverflow.ellipsis, + maxLines: 2, + TextSpan( + children: [ + if (replies![index].isUp) + TextSpan( + text: 'UP • ', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: Theme.of(context) + .textTheme + .labelMedium! + .fontSize, + color: Theme.of(context).colorScheme.primary, + ), + ), + TextSpan( + text: replies![index].member.uname + ' ', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .titleSmall! + .fontSize, + color: Theme.of(context).colorScheme.primary, + ), + recognizer: TapGestureRecognizer() + ..onTap = () => { + print('跳转至用户主页'), + }, + ), + buildContent(context, replies![index].content), + ], + ), + ), + )); + } + }, + ), + ), + ); + } +} + +InlineSpan buildContent(BuildContext context, content) { + if (content.emote.isEmpty && + content.atNameToMid.isEmpty && + content.jumpUrl.isEmpty && + content.pictures.isEmpty) { + return TextSpan(text: content.message); + } + List spanChilds = []; + // if (content.atNameToMid.isNotEmpty) { + // print(content.message); + // content.atNameToMid.forEach((key, value) { + // key = '@' + key; + // int lastIndex = content.message.indexOf(key); + // int endIndex = (lastIndex + key.length).toInt(); + // if (lastIndex >= 0) { + // spanChilds.add(TextSpan( + // text: '@' + key, + // style: TextStyle(color: Theme.of(context).colorScheme.primary))); + // content.message = content.message.replaceRange(lastIndex, endIndex, ''); + // spanChilds.add(TextSpan(text: content.message)); + // } + // spanChilds.add(TextSpan(text: content.message.substring(lastIndex))); + // }); + // // return TextSpan(children: spanChilds); + // } + // if (content.emote.isNotEmpty) { + // content.emote.forEach((key, value) { + // int lastIndex = content.message.indexOf(key); + // int endIndex = content.message.indexOf(key) + key.length; + // if (lastIndex >= 0) { + // content.message = content.message.replaceRange(lastIndex, endIndex, ''); + // spanChilds.add(TextSpan(text: content.message.substring(0, lastIndex))); + // } + // spanChilds.add(WidgetSpan( + // child: NetworkImgLayer( + // src: value["url"], + // width: 20, + // height: 20, + // ))); + // }); + // // return TextSpan(children: spanChilds); + // } + // if (content.pictures.isNotEmpty) { + // spanChilds.add(TextSpan(text: content.message)); + // spanChilds.add(const WidgetSpan( + // child: SizedBox( + // height: 4, + // ))); + // for (var i = 0; i < content.pictures.length; i++) { + // spanChilds.add( + // WidgetSpan( + // child: SizedBox( + // height: 180, + // child: NetworkImgLayer( + // src: content.pictures[i]['img_src'], + // width: 200, + // height: 200 * + // content.pictures[i]['img_height'] / + // content.pictures[i]['img_width'], + // ), + // ), + // ), + // ); + // } + // return TextSpan(children: spanChilds); + // } + content.message.splitMapJoin( + RegExp(r"\[.*?\]"), + onMatch: (Match match) { + String matchStr = match[0]!; + if (content.emote.isNotEmpty) { + if (content.emote.keys.contains(matchStr)) { + spanChilds.add( + WidgetSpan( + child: NetworkImgLayer( + src: content.emote[matchStr]['url'], + width: 20, + height: 20, + ), + ), + ); + } else { + spanChilds.add(TextSpan(text: matchStr)); + return matchStr; + } + } + return matchStr; + }, + onNonMatch: (String str) { + try { + if (content.atNameToMid.isNotEmpty) { + return str.splitMapJoin( + RegExp(r"@.*:"), + onMatch: (Match match) { + if (match[0] != null) { + content.atNameToMid.forEach((key, value) { + spanChilds.add( + TextSpan( + text: '@$key ', + style: TextStyle( + fontSize: + Theme.of(context).textTheme.titleSmall!.fontSize, + color: Theme.of(context).colorScheme.primary, + ), + recognizer: TapGestureRecognizer() + ..onTap = () => { + print('跳转至用户主页'), + }, + ), + ); + }); + } + return match[0]!; + }, + onNonMatch: (String str) { + spanChilds.add(TextSpan(text: str)); + return str; + }, + ); + } else { + spanChilds.add(TextSpan(text: str)); + return str; + } + } catch (e) { + spanChilds.add(TextSpan(text: str)); + return str; + } + }, + ); + if (content.pictures.isNotEmpty) { + spanChilds.add(const WidgetSpan( + child: SizedBox( + height: 4, + ))); + for (var i = 0; i < content.pictures.length; i++) { + spanChilds.add( + WidgetSpan( + child: SizedBox( + height: 180, + child: NetworkImgLayer( + src: content.pictures[i]['img_src'], + width: 200, + height: 200 * + content.pictures[i]['img_height'] / + content.pictures[i]['img_width'], + ), + ), + ), + ); + } + } + return TextSpan(children: spanChilds); +}