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); }