opt: reply item

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-11-28 15:24:28 +08:00
parent 25fc85bd3a
commit 1f71dc9a67
8 changed files with 79 additions and 105 deletions

View File

@@ -110,7 +110,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
} }
// 查看二级评论 // 查看二级评论
void replyReply(replyItem, id) { void replyReply(replyItem, id, isTop) {
int oid = replyItem.oid.toInt(); int oid = replyItem.oid.toInt();
int rpid = replyItem.id.toInt()!; int rpid = replyItem.id.toInt()!;
Get.to( Get.to(
@@ -124,6 +124,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
source: 'dynamic', source: 'dynamic',
replyType: ReplyType.values[replyType], replyType: ReplyType.values[replyType],
firstFloor: replyItem, firstFloor: replyItem,
isTop: isTop,
), ),
), ),
); );

View File

@@ -109,7 +109,7 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
} }
} }
void replyReply(replyItem, id) { void replyReply(replyItem, id, isTop) {
int oid = replyItem.oid.toInt(); int oid = replyItem.oid.toInt();
int rpid = replyItem.id.toInt(); int rpid = replyItem.id.toInt();
Get.to( Get.to(
@@ -125,6 +125,7 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
source: 'dynamic', source: 'dynamic',
replyType: ReplyType.values[type], replyType: ReplyType.values[type],
firstFloor: replyItem, firstFloor: replyItem,
isTop: isTop,
), ),
), ),
); );

View File

@@ -1321,18 +1321,13 @@ class VideoDetailController extends GetxController
.primary, .primary,
), ),
), ),
SizedBox( Icon(
height: MediaQuery Icons
.textScalerOf( .keyboard_arrow_right,
context) size: 22,
.scale(14), color: Theme.of(context)
child: Icon( .colorScheme
Icons .primary,
.keyboard_arrow_right,
color: Theme.of(context)
.colorScheme
.primary,
),
), ),
], ],
), ),
@@ -1387,19 +1382,14 @@ class VideoDetailController extends GetxController
.primary, .primary,
), ),
), ),
SizedBox( Icon(
height: MediaQuery Icons
.textScalerOf( .keyboard_arrow_right,
context) size: 22,
.scale(14), color: Theme.of(context)
child: Icon( .colorScheme
Icons .primary,
.keyboard_arrow_right, ),
color: Theme.of(context)
.colorScheme
.primary,
),
)
], ],
), ),
), ),

View File

@@ -48,9 +48,7 @@ class ReplyItem extends StatelessWidget {
// 点击整个评论区 评论详情/回复 // 点击整个评论区 评论详情/回复
onTap: () { onTap: () {
feedBack(); feedBack();
if (replyReply != null) { replyReply?.call(replyItem);
replyReply!(replyItem);
}
}, },
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
@@ -434,7 +432,7 @@ class ReplyItemRow extends StatelessWidget {
for (int i = 0; i < replies!.length; i++) ...[ for (int i = 0; i < replies!.length; i++) ...[
InkWell( InkWell(
// 一楼点击评论展开评论详情 // 一楼点击评论展开评论详情
onTap: () => replyReply!(replyItem), onTap: () => replyReply?.call(replyItem),
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
showModalBottomSheet( showModalBottomSheet(
@@ -534,7 +532,7 @@ class ReplyItemRow extends StatelessWidget {
if (extraRow == 1) if (extraRow == 1)
InkWell( InkWell(
// 一楼点击【共xx条回复】展开评论详情 // 一楼点击【共xx条回复】展开评论详情
onTap: () => replyReply!(replyItem), onTap: () => replyReply?.call(replyItem),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.fromLTRB(8, 5, 8, 8), padding: const EdgeInsets.fromLTRB(8, 5, 8, 8),

View File

@@ -10,7 +10,6 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/models/common/reply_type.dart'; import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/pages/video/detail/index.dart'; import 'package:PiliPalaX/pages/video/detail/index.dart';
@@ -20,8 +19,6 @@ import 'package:PiliPalaX/utils/url_utils.dart';
import 'package:PiliPalaX/utils/utils.dart'; import 'package:PiliPalaX/utils/utils.dart';
import '../../../../../utils/app_scheme.dart'; import '../../../../../utils/app_scheme.dart';
Box setting = GStorage.setting;
class ReplyItemGrpc extends StatelessWidget { class ReplyItemGrpc extends StatelessWidget {
const ReplyItemGrpc({ const ReplyItemGrpc({
super.key, super.key,
@@ -59,9 +56,7 @@ class ReplyItemGrpc extends StatelessWidget {
// 点击整个评论区 评论详情/回复 // 点击整个评论区 评论详情/回复
onTap: () { onTap: () {
feedBack(); feedBack();
if (replyReply != null) { replyReply?.call(replyItem, null, isTop);
replyReply!(replyItem, null);
}
}, },
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
@@ -318,20 +313,8 @@ class ReplyItemGrpc extends StatelessWidget {
showReplyRow) ...[ showReplyRow) ...[
Padding( Padding(
padding: const EdgeInsets.only(top: 5, bottom: 12), padding: const EdgeInsets.only(top: 5, bottom: 12),
child: ReplyItemRow( child: replyItemRow(
upMid: upMid, context: context,
count: replyItem.count.toInt(),
replies: replyItem.replies,
replyControl: replyItem.replyControl,
// f_rpid: replyItem.rpid,
replyItem: replyItem,
replyReply: replyReply,
onDelete: (rpid) {
if (onDelete != null) {
onDelete!(rpid, replyItem.id.toInt());
}
},
getTag: getTag,
), ),
), ),
], ],
@@ -430,35 +413,9 @@ class ReplyItemGrpc extends StatelessWidget {
], ],
); );
} }
}
// ignore: must_be_immutable Widget replyItemRow({required BuildContext context}) {
class ReplyItemRow extends StatelessWidget { final bool extraRow = replyItem.replies.length < replyItem.count.toInt();
ReplyItemRow({
super.key,
required this.count,
required this.replies,
required this.replyControl,
// this.f_rpid,
this.replyItem,
this.replyReply,
this.onDelete,
this.upMid,
this.getTag,
});
final int count;
final List<ReplyInfo> replies;
ReplyControl replyControl;
// int? f_rpid;
ReplyInfo? replyItem;
Function? replyReply;
final Function(dynamic rpid)? onDelete;
final dynamic upMid;
final Function? getTag;
@override
Widget build(BuildContext context) {
final bool extraRow = replies.length < count;
return Container( return Container(
margin: const EdgeInsets.only(left: 42, right: 4, top: 0), margin: const EdgeInsets.only(left: 42, right: 4, top: 0),
child: Material( child: Material(
@@ -469,12 +426,12 @@ class ReplyItemRow extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (replies.isNotEmpty) if (replyItem.replies.isNotEmpty)
for (int i = 0; i < replies.length; i++) ...[ for (int i = 0; i < replyItem.replies.length; i++) ...[
InkWell( InkWell(
// 一楼点击评论展开评论详情 // 一楼点击评论展开评论详情
onTap: () => onTap: () => replyReply?.call(
replyReply?.call(replyItem, replies[i].id.toInt()), replyItem, replyItem.replies[i].id.toInt(), isTop),
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
showModalBottomSheet( showModalBottomSheet(
@@ -483,8 +440,10 @@ class ReplyItemRow extends StatelessWidget {
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return MorePanel( return MorePanel(
item: replies[i], item: replyItem.replies[i],
onDelete: onDelete, onDelete: (rpid) {
onDelete?.call(rpid, replyItem.id.toInt());
},
); );
}, },
); );
@@ -493,13 +452,17 @@ class ReplyItemRow extends StatelessWidget {
width: double.infinity, width: double.infinity,
padding: EdgeInsets.fromLTRB( padding: EdgeInsets.fromLTRB(
8, 8,
i == 0 && (extraRow || replies.length > 1) ? 8 : 4, i == 0 && (extraRow || replyItem.replies.length > 1)
? 8
: 4,
8, 8,
i == 0 && (extraRow || replies.length > 1) ? 4 : 6, i == 0 && (extraRow || replyItem.replies.length > 1)
? 4
: 6,
), ),
child: Semantics( child: Semantics(
label: label:
'${replies[i].member.name} ${replies[i].content.message}', '${replyItem.replies[i].member.name} ${replyItem.replies[i].content.message}',
excludeSemantics: true, excludeSemantics: true,
child: Text.rich( child: Text.rich(
style: TextStyle( style: TextStyle(
@@ -517,7 +480,7 @@ class ReplyItemRow extends StatelessWidget {
TextSpan( TextSpan(
children: [ children: [
TextSpan( TextSpan(
text: replies[i].member.name, text: replyItem.replies[i].member.name,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
@@ -527,17 +490,18 @@ class ReplyItemRow extends StatelessWidget {
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
feedBack(); feedBack();
final String heroTag = final String heroTag = Utils.makeHeroTag(
Utils.makeHeroTag(replies[i].member.mid); replyItem.replies[i].member.mid);
Get.toNamed( Get.toNamed(
'/member?mid=${replies[i].member.mid}', '/member?mid=${replyItem.replies[i].member.mid}',
arguments: { arguments: {
'face': replies[i].member.face, 'face':
replyItem.replies[i].member.face,
'heroTag': heroTag 'heroTag': heroTag
}); });
}, },
), ),
if (replies[i].mid == upMid) ...[ if (replyItem.replies[i].mid == upMid) ...[
const TextSpan(text: ' '), const TextSpan(text: ' '),
const WidgetSpan( const WidgetSpan(
alignment: PlaceholderAlignment.top, alignment: PlaceholderAlignment.top,
@@ -551,15 +515,16 @@ class ReplyItemRow extends StatelessWidget {
const TextSpan(text: ' '), const TextSpan(text: ' '),
], ],
TextSpan( TextSpan(
text: replies[i].root == replies[i].parent text: replyItem.replies[i].root ==
replyItem.replies[i].parent
? ': ' ? ': '
: replies[i].mid == upMid : replyItem.replies[i].mid == upMid
? '' ? ''
: ' ', : ' ',
), ),
buildContent( buildContent(
context, context,
replies[i], replyItem.replies[i],
replyReply, replyReply,
replyItem, replyItem,
null, null,
@@ -576,7 +541,7 @@ class ReplyItemRow extends StatelessWidget {
if (extraRow) if (extraRow)
InkWell( InkWell(
// 一楼点击【共xx条回复】展开评论详情 // 一楼点击【共xx条回复】展开评论详情
onTap: () => replyReply!(replyItem, null), onTap: () => replyReply?.call(replyItem, null, isTop),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.fromLTRB(8, 5, 8, 8), padding: const EdgeInsets.fromLTRB(8, 5, 8, 8),
@@ -587,7 +552,7 @@ class ReplyItemRow extends StatelessWidget {
Theme.of(context).textTheme.labelMedium!.fontSize, Theme.of(context).textTheme.labelMedium!.fontSize,
), ),
children: [ children: [
if (replyControl.upReply) if (replyItem.replyControl.upReply)
TextSpan( TextSpan(
text: 'UP主等人 ', text: 'UP主等人 ',
style: TextStyle( style: TextStyle(
@@ -596,7 +561,7 @@ class ReplyItemRow extends StatelessWidget {
.onSurface .onSurface
.withOpacity(0.85))), .withOpacity(0.85))),
TextSpan( TextSpan(
text: replyControl.subReplyEntryText, text: replyItem.replyControl.subReplyEntryText,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
@@ -703,6 +668,7 @@ InlineSpan buildContent(
if (jumpUrlKeysList.isNotEmpty) { if (jumpUrlKeysList.isNotEmpty) {
patternStr += '|${jumpUrlKeysList.map(RegExp.escape).join('|')}'; patternStr += '|${jumpUrlKeysList.map(RegExp.escape).join('|')}';
} }
patternStr += r'|https://b23\.tv/[a-zA-Z0-9]{7}';
final RegExp pattern = RegExp(patternStr); final RegExp pattern = RegExp(patternStr);
List<String> matchedStrs = []; List<String> matchedStrs = [];
void addPlainTextSpan(str) { void addPlainTextSpan(str) {
@@ -807,10 +773,24 @@ InlineSpan buildContent(
: null, : null,
), ),
); );
} else if (matchStr.startsWith('https://b23.tv/')) {
spanChildren.add(
TextSpan(
text: ' $matchStr ',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () => Get.toNamed(
'/webviewnew',
parameters: {'url': matchStr},
),
),
);
} else { } else {
String appUrlSchema = ''; String appUrlSchema = '';
final bool enableWordRe = setting.get(SettingBoxKey.enableWordRe, final bool enableWordRe = GStorage.setting
defaultValue: false) as bool; .get(SettingBoxKey.enableWordRe, defaultValue: false) as bool;
if (content.url[matchStr] != null && !matchedStrs.contains(matchStr)) { if (content.url[matchStr] != null && !matchedStrs.contains(matchStr)) {
appUrlSchema = content.url[matchStr]!.appUrlSchema; appUrlSchema = content.url[matchStr]!.appUrlSchema;
if (appUrlSchema.startsWith('bilibili://search') && !enableWordRe) { if (appUrlSchema.startsWith('bilibili://search') && !enableWordRe) {

View File

@@ -27,6 +27,7 @@ class VideoReplyReplyPanel extends StatefulWidget {
this.source, this.source,
this.replyType, this.replyType,
this.isDialogue = false, this.isDialogue = false,
this.isTop = false,
super.key, super.key,
}); });
// final dynamic rcount; // final dynamic rcount;
@@ -38,6 +39,7 @@ class VideoReplyReplyPanel extends StatefulWidget {
final String? source; final String? source;
final ReplyType? replyType; final ReplyType? replyType;
final bool isDialogue; final bool isDialogue;
final bool isTop;
@override @override
State<VideoReplyReplyPanel> createState() => _VideoReplyReplyPanelState(); State<VideoReplyReplyPanel> createState() => _VideoReplyReplyPanelState();
@@ -164,6 +166,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
_onReply(firstFloor!, -1); _onReply(firstFloor!, -1);
}, },
upMid: _videoReplyReplyController.upMid, upMid: _videoReplyReplyController.upMid,
isTop: widget.isTop,
); );
} else if (index == 1) { } else if (index == 1) {
return Divider( return Divider(

View File

@@ -1311,7 +1311,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
); );
// 展示二级回复 // 展示二级回复
void replyReply(replyItem, id) { void replyReply(replyItem, id, isTop) {
videoDetailController.childKey.currentState?.showBottomSheet( videoDetailController.childKey.currentState?.showBottomSheet(
(context) => VideoReplyReplyPanel( (context) => VideoReplyReplyPanel(
id: id, id: id,
@@ -1321,6 +1321,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
firstFloor: replyItem, firstFloor: replyItem,
replyType: ReplyType.video, replyType: ReplyType.video,
source: 'videoDetail', source: 'videoDetail',
isTop: isTop,
), ),
); );
} }

View File

@@ -27,7 +27,7 @@ class Utils {
static final Random random = Random(); static final Random random = Random();
static bool isStringNumeric(str) { static bool isStringNumeric(str) {
RegExp numericRegex = RegExp(r'^\d+$'); RegExp numericRegex = RegExp(r'^[\d\.]+$');
return numericRegex.hasMatch(str.toString()); return numericRegex.hasMatch(str.toString());
} }