opt: grpc reply item

This commit is contained in:
bggRGjQaUbCoE
2024-10-11 23:05:48 +08:00
parent a762334772
commit 60e80ba160
8 changed files with 392 additions and 403 deletions

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
@@ -124,15 +125,15 @@ abstract class ReplyController extends CommonController {
dynamic replyItem,
int index = 0,
}) {
dynamic key = oid ?? replyItem.oid + replyItem.rpid;
dynamic key = oid ?? replyItem.oid + replyItem.id;
Navigator.of(context)
.push(
GetDialogRoute(
pageBuilder: (buildContext, animation, secondaryAnimation) {
return ReplyPage(
oid: oid ?? replyItem.oid,
root: oid != null ? 0 : replyItem.rpid,
parent: oid != null ? 0 : replyItem.rpid,
oid: oid ?? replyItem.oid.toInt(),
root: oid != null ? 0 : replyItem.id.toInt(),
parent: oid != null ? 0 : replyItem.id.toInt(),
replyType: ReplyType.video,
replyItem: replyItem,
savedReply: savedReplies[key],
@@ -159,35 +160,37 @@ abstract class ReplyController extends CommonController {
)
.then(
(value) {
if (value != null && value['data'] != null) {
// TODO: data cast
if (value != null && value['data'] is ReplyInfo) {
savedReplies[key] = null;
List list = loadingState.value is Success
? (loadingState.value as Success).response
: [];
MainListReply response =
(loadingState.value as Success?)?.response ?? MainListReply();
if (oid != null) {
list.insert(0, value['data']);
response.replies.insert(0, value['data']);
} else {
list[index].replies.add(value['data']);
response.replies[index].replies.add(value['data']);
}
loadingState.value = LoadingState.success(list);
loadingState.value = LoadingState.success(response);
}
},
);
}
onMDelete(rpid, frpid) {
List list = (loadingState.value as Success).response;
list = frpid == null
? list.where((item) => item.rpid != rpid).toList()
: list.map((item) {
if (item.rpid == frpid) {
return item
..replies =
item.replies?.where((reply) => reply.rpid != rpid).toList();
} else {
return item;
}
}).toList();
loadingState.value = LoadingState.success(list);
MainListReply response = (loadingState.value as Success).response;
if (frpid == null) {
response.replies.removeWhere((item) {
return item.id.toInt() == rpid;
});
} else {
response.replies.map((item) {
if (item.id == frpid) {
return item..replies.removeWhere((reply) => reply.id.toInt() == rpid);
} else {
return item;
}
}).toList();
}
loadingState.value = LoadingState.success(response);
}
}

View File

@@ -1,18 +1,11 @@
import 'dart:convert';
import 'dart:ffi';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/common/reply_sort_type.dart';
import 'package:PiliPalaX/pages/common/reply_controller.dart';
import 'package:PiliPalaX/http/reply.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:fixnum/fixnum.dart' as $fixnum;
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class VideoReplyController extends ReplyController {
VideoReplyController(

View File

@@ -10,7 +10,6 @@ import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/id_utils.dart';
import 'controller.dart';
import 'widgets/reply_item.dart';
class VideoReplyPanel extends StatefulWidget {
final String? bvid;

View File

@@ -1,10 +1,7 @@
import 'dart:convert';
import 'package:PiliPalaX/common/widgets/badge.dart';
import 'package:PiliPalaX/common/widgets/imageview.dart';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/http/video.dart';
import 'package:PiliPalaX/pages/video/detail/reply/widgets/zan.dart';
import 'package:PiliPalaX/pages/video/detail/reply/widgets/zan_grpc.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
@@ -261,8 +258,7 @@ class ReplyItemGrpc extends StatelessWidget {
String text = replyItem.content.message;
var textPainter = TextPainter(
text: TextSpan(text: text),
maxLines: 6,
// replyItem.content!.isText! && replyLevel == '1' ? 6 : null,
maxLines: replyLevel == '1' ? 6 : null,
textDirection: Directionality.of(context),
)..layout(maxWidth: constraints.maxWidth);
bool didExceedMaxLines = textPainter.didExceedMaxLines;
@@ -322,6 +318,7 @@ class ReplyItemGrpc extends StatelessWidget {
padding: const EdgeInsets.only(top: 5, bottom: 12),
child: ReplyItemRow(
upMid: upMid,
count: replyItem.count.toInt(),
replies: replyItem.replies,
replyControl: replyItem.replyControl,
// f_rpid: replyItem.rpid,
@@ -329,7 +326,7 @@ class ReplyItemGrpc extends StatelessWidget {
replyReply: replyReply,
onDelete: (rpid) {
if (onDelete != null) {
onDelete!(rpid, replyItem.id);
onDelete!(rpid, replyItem.id.toInt());
}
},
),
@@ -410,6 +407,7 @@ class ReplyItemGrpc extends StatelessWidget {
class ReplyItemRow extends StatelessWidget {
ReplyItemRow({
super.key,
required this.count,
required this.replies,
required this.replyControl,
// this.f_rpid,
@@ -418,6 +416,7 @@ class ReplyItemRow extends StatelessWidget {
this.onDelete,
this.upMid,
});
final int count;
final List<ReplyInfo> replies;
ReplyControl replyControl;
// int? f_rpid;
@@ -428,7 +427,7 @@ class ReplyItemRow extends StatelessWidget {
@override
Widget build(BuildContext context) {
final bool extraRow = replyControl.subReplyEntryText.isNotEmpty;
final bool extraRow = replies.length < count;
return Container(
margin: const EdgeInsets.only(left: 42, right: 4, top: 0),
child: Material(
@@ -614,35 +613,35 @@ InlineSpan buildContent(
message = message.substring(0, endOffset);
}
return TextSpan(text: message);
// return TextSpan(text: message);
// 投票
// if (content.vote.isNotEmpty) {
// message.splitMapJoin(RegExp(r"\{vote:\d+?\}"), onMatch: (Match match) {
// // String matchStr = match[0]!;
// spanChildren.add(
// TextSpan(
// text: '投票: ${content.vote['title']}',
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// ),
// recognizer: TapGestureRecognizer()
// ..onTap = () => Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': content.vote['url'],
// 'type': 'vote',
// 'pageTitle': content.vote['title'],
// },
// ),
// ),
// );
// return '';
// }, onNonMatch: (String str) {
// return str;
// });
// message = message.replaceAll(RegExp(r"\{vote:\d+?\}"), "");
// }
if (content.hasVote()) {
message.splitMapJoin(RegExp(r"\{vote:\d+?\}"), onMatch: (Match match) {
// String matchStr = match[0]!;
spanChildren.add(
TextSpan(
text: '投票: ${content.vote.title}',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()..onTap = () {}
// Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': content.vote['url'],
// 'type': 'vote',
// 'pageTitle': content.vote.title,
// },
// ),
),
);
return '';
}, onNonMatch: (String str) {
return str;
});
message = message.replaceAll(RegExp(r"\{vote:\d+?\}"), "");
}
message = message
.replaceAll('&amp;', '&')
.replaceAll('&lt;', '<')
@@ -653,22 +652,22 @@ InlineSpan buildContent(
// 构建正则表达式
final List<String> specialTokens = [
...content.emote.keys,
// ...content.topicsMeta?.keys?.map((e) => '#$e#') ?? [],
...content.topic.keys.map((e) => '#$e#'),
...content.atNameToMid.keys.map((e) => '@$e'),
];
// List<String> jumpUrlKeysList = content.jumpUrl.keys.map<String>((String e) {
// return e.replaceAllMapped(
// RegExp(r'[?+*]'), (match) => '\\${match.group(0)}');
// }).toList();
List<String> jumpUrlKeysList = content.url.keys.map<String>((String e) {
return e.replaceAllMapped(
RegExp(r'[?+*]'), (match) => '\\${match.group(0)}');
}).toList();
specialTokens.sort((a, b) => b.length.compareTo(a.length));
String patternStr = specialTokens.map(RegExp.escape).join('|');
if (patternStr.isNotEmpty) {
patternStr += "|";
}
patternStr += r'(\b(?:\d+[:])?[0-5]?[0-9][:][0-5]?[0-9]\b)';
// if (jumpUrlKeysList.isNotEmpty) {
// patternStr += '|${jumpUrlKeysList.map(RegExp.escape).join('|')}';
// }
if (jumpUrlKeysList.isNotEmpty) {
patternStr += '|${jumpUrlKeysList.map(RegExp.escape).join('|')}';
}
final RegExp pattern = RegExp(patternStr);
List<String> matchedStrs = [];
void addPlainTextSpan(str) {
@@ -684,304 +683,302 @@ InlineSpan buildContent(
}
// 分割文本并处理每个部分
// message.splitMapJoin(
// pattern,
// onMatch: (Match match) {
// String matchStr = match[0]!;
// if (content.emote.containsKey(matchStr)) {
// // 处理表情
// final int size = content.emote[matchStr]['meta']['size'];
// spanChildren.add(WidgetSpan(
// child: ExcludeSemantics(
// child: NetworkImgLayer(
// src: content.emote[matchStr]['url'],
// type: 'emote',
// width: size * 20,
// height: size * 20,
// semanticsLabel: matchStr,
// )),
// ));
// } else if (matchStr.startsWith("@") &&
// content.atNameToMid.containsKey(matchStr.substring(1))) {
// // 处理@用户
// final String userName = matchStr.substring(1);
// final int userId = content.atNameToMid[userName];
// spanChildren.add(
// TextSpan(
// text: matchStr,
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// ),
// recognizer: TapGestureRecognizer()
// ..onTap = () {
// final String heroTag = Utils.makeHeroTag(userId);
// Get.toNamed(
// '/member?mid=$userId',
// arguments: {'face': '', 'heroTag': heroTag},
// );
// },
// ),
// );
// } else if (RegExp(r'^\b(?:\d+[:])?[0-5]?[0-9][:][0-5]?[0-9]\b$')
// .hasMatch(matchStr)) {
// matchStr = matchStr.replaceAll('', ':');
// spanChildren.add(
// TextSpan(
// text: ' $matchStr ',
// style: isVideoPage
// ? TextStyle(
// color: Theme.of(context).colorScheme.primary,
// )
// : null,
// recognizer: TapGestureRecognizer()
// ..onTap = () {
// // 跳转到指定位置
// if (isVideoPage) {
// try {
// SmartDialog.showToast('跳转至:$matchStr');
// Get.find<VideoDetailController>(
// tag: Get.arguments['heroTag'])
// .plPlayerController
// .seekTo(Duration(seconds: Utils.duration(matchStr)),
// type: 'slider');
// } catch (e) {
// SmartDialog.showToast('跳转失败: $e');
// }
// }
// },
// ),
// );
// } else {
// String appUrlSchema = '';
// final bool enableWordRe = setting.get(SettingBoxKey.enableWordRe,
// defaultValue: false) as bool;
// if (content.jumpUrl[matchStr] != null &&
// !matchedStrs.contains(matchStr)) {
// appUrlSchema = content.jumpUrl[matchStr]['app_url_schema'];
// if (appUrlSchema.startsWith('bilibili://search') && !enableWordRe) {
// addPlainTextSpan(matchStr);
// return "";
// }
// spanChildren.addAll(
// [
// if (content.jumpUrl[matchStr]?['prefix_icon'] != null) ...[
// WidgetSpan(
// child: Image.network(
// content.jumpUrl[matchStr]['prefix_icon'],
// height: 19,
// color: Theme.of(context).colorScheme.primary,
// ),
// )
// ],
// TextSpan(
// text: content.jumpUrl[matchStr]['title'],
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// ),
// recognizer: TapGestureRecognizer()
// ..onTap = () async {
// final String title = content.jumpUrl[matchStr]['title'];
// if (appUrlSchema == '') {
// if (matchStr.startsWith('BV')) {
// UrlUtils.matchUrlPush(
// matchStr,
// title,
// '',
// );
// } else if (RegExp(r'^[Cc][Vv][0-9]+$')
// .hasMatch(matchStr)) {
// Get.toNamed('/htmlRender', parameters: {
// 'url': 'https://www.bilibili.com/read/$matchStr',
// 'title': title,
// 'id': matchStr,
// 'dynamicType': 'read'
// });
// } else {
// final String redirectUrl =
// await UrlUtils.parseRedirectUrl(matchStr);
// // if (redirectUrl == matchStr) {
// // Clipboard.setData(ClipboardData(text: matchStr));
// // SmartDialog.showToast('地址可能有误');
// // return;
// // }
// Uri uri = Uri.parse(redirectUrl);
// PiliScheme.routePush(uri);
// // final String pathSegment = Uri.parse(redirectUrl).path;
// // final String lastPathSegment =
// // pathSegment.split('/').last;
// // if (lastPathSegment.startsWith('BV')) {
// // UrlUtils.matchUrlPush(
// // lastPathSegment,
// // title,
// // redirectUrl,
// // );
// // } else {
// // Get.toNamed(
// // '/webviewnew',
// // parameters: {
// // 'url': redirectUrl,
// // 'type': 'url',
// // 'pageTitle': title
// // },
// // );
// // }
// }
// } else {
// if (appUrlSchema.startsWith('bilibili://search')) {
// Get.toNamed('/searchResult',
// parameters: {'keyword': title});
// } else if (matchStr.startsWith('https://b23.tv')) {
// final String redirectUrl =
// await UrlUtils.parseRedirectUrl(matchStr);
// final String pathSegment = Uri.parse(redirectUrl).path;
// final String lastPathSegment =
// pathSegment.split('/').last;
// if (lastPathSegment.startsWith('BV')) {
// UrlUtils.matchUrlPush(
// lastPathSegment,
// title,
// redirectUrl,
// );
// } else {
// Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': redirectUrl,
// 'type': 'url',
// 'pageTitle': title
// },
// );
// }
// } else {
// Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': matchStr,
// 'type': 'url',
// 'pageTitle': title
// },
// );
// }
// }
// },
// )
// ],
// );
// // 只显示一次
// matchedStrs.add(matchStr);
// } else if (matchStr.length > 1 &&
// content.topicsMeta[matchStr.substring(1, matchStr.length - 1)] !=
// null) {
// spanChildren.add(
// TextSpan(
// text: matchStr,
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// ),
// recognizer: TapGestureRecognizer()
// ..onTap = () {
// final String topic =
// matchStr.substring(1, matchStr.length - 1);
// Get.toNamed('/searchResult', parameters: {'keyword': topic});
// },
// ),
// );
// } else {
// addPlainTextSpan(matchStr);
// }
// }
// return '';
// },
// onNonMatch: (String nonMatchStr) {
// addPlainTextSpan(nonMatchStr);
// return nonMatchStr;
// },
// );
message.splitMapJoin(
pattern,
onMatch: (Match match) {
String matchStr = match[0]!;
if (content.emote.containsKey(matchStr)) {
// 处理表情
final int size = content.emote[matchStr]!.size.toInt();
spanChildren.add(WidgetSpan(
child: ExcludeSemantics(
child: NetworkImgLayer(
src: content.emote[matchStr]!.url,
type: 'emote',
width: size * 20,
height: size * 20,
semanticsLabel: matchStr,
)),
));
} else if (matchStr.startsWith("@") &&
content.atNameToMid.containsKey(matchStr.substring(1))) {
// 处理@用户
final String userName = matchStr.substring(1);
final int userId = content.atNameToMid[userName]!.toInt();
spanChildren.add(
TextSpan(
text: matchStr,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
final String heroTag = Utils.makeHeroTag(userId);
Get.toNamed(
'/member?mid=$userId',
arguments: {'face': '', 'heroTag': heroTag},
);
},
),
);
} else if (RegExp(r'^\b(?:\d+[:])?[0-5]?[0-9][:][0-5]?[0-9]\b$')
.hasMatch(matchStr)) {
matchStr = matchStr.replaceAll('', ':');
spanChildren.add(
TextSpan(
text: ' $matchStr ',
style: isVideoPage
? TextStyle(
color: Theme.of(context).colorScheme.primary,
)
: null,
recognizer: TapGestureRecognizer()
..onTap = () {
// 跳转到指定位置
if (isVideoPage) {
try {
SmartDialog.showToast('跳转至:$matchStr');
Get.find<VideoDetailController>(
tag: Get.arguments['heroTag'])
.plPlayerController
.seekTo(Duration(seconds: Utils.duration(matchStr)),
type: 'slider');
} catch (e) {
SmartDialog.showToast('跳转失败: $e');
}
}
},
),
);
} else {
String appUrlSchema = '';
final bool enableWordRe = setting.get(SettingBoxKey.enableWordRe,
defaultValue: false) as bool;
if (content.url[matchStr] != null && !matchedStrs.contains(matchStr)) {
appUrlSchema = content.url[matchStr]!.appUrlSchema;
if (appUrlSchema.startsWith('bilibili://search') && !enableWordRe) {
addPlainTextSpan(matchStr);
return "";
}
spanChildren.addAll(
[
if (content.url[matchStr]?.hasPrefixIcon() == true) ...[
WidgetSpan(
child: Image.network(
content.url[matchStr]!.prefixIcon,
height: 19,
color: Theme.of(context).colorScheme.primary,
),
)
],
TextSpan(
text: content.url[matchStr]!.title,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () async {
final String title = content.url[matchStr]!.title;
if (appUrlSchema == '') {
if (matchStr.startsWith('BV')) {
UrlUtils.matchUrlPush(
matchStr,
title,
'',
);
} else if (RegExp(r'^[Cc][Vv][0-9]+$')
.hasMatch(matchStr)) {
Get.toNamed('/htmlRender', parameters: {
'url': 'https://www.bilibili.com/read/$matchStr',
'title': title,
'id': matchStr,
'dynamicType': 'read'
});
} else {
final String redirectUrl =
await UrlUtils.parseRedirectUrl(matchStr);
// if (redirectUrl == matchStr) {
// Clipboard.setData(ClipboardData(text: matchStr));
// SmartDialog.showToast('地址可能有误');
// return;
// }
Uri uri = Uri.parse(redirectUrl);
PiliScheme.routePush(uri);
// final String pathSegment = Uri.parse(redirectUrl).path;
// final String lastPathSegment =
// pathSegment.split('/').last;
// if (lastPathSegment.startsWith('BV')) {
// UrlUtils.matchUrlPush(
// lastPathSegment,
// title,
// redirectUrl,
// );
// } else {
// Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': redirectUrl,
// 'type': 'url',
// 'pageTitle': title
// },
// );
// }
}
} else {
if (appUrlSchema.startsWith('bilibili://search')) {
Get.toNamed('/searchResult',
parameters: {'keyword': title});
} else if (matchStr.startsWith('https://b23.tv')) {
final String redirectUrl =
await UrlUtils.parseRedirectUrl(matchStr);
final String pathSegment = Uri.parse(redirectUrl).path;
final String lastPathSegment =
pathSegment.split('/').last;
if (lastPathSegment.startsWith('BV')) {
UrlUtils.matchUrlPush(
lastPathSegment,
title,
redirectUrl,
);
} else {
Get.toNamed(
'/webviewnew',
parameters: {
'url': redirectUrl,
'type': 'url',
'pageTitle': title
},
);
}
} else {
Get.toNamed(
'/webviewnew',
parameters: {
'url': matchStr,
'type': 'url',
'pageTitle': title
},
);
}
}
},
)
],
);
// 只显示一次
matchedStrs.add(matchStr);
} else if (matchStr.length > 1 &&
content.topic[matchStr.substring(1, matchStr.length - 1)] != null) {
spanChildren.add(
TextSpan(
text: matchStr,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
final String topic =
matchStr.substring(1, matchStr.length - 1);
Get.toNamed('/searchResult', parameters: {'keyword': topic});
},
),
);
} else {
addPlainTextSpan(matchStr);
}
}
return '';
},
onNonMatch: (String nonMatchStr) {
addPlainTextSpan(nonMatchStr);
return nonMatchStr;
},
);
// if (content.jumpUrl.keys.isNotEmpty) {
// List<String> unmatchedItems = content.jumpUrl.keys
// .toList()
// .where((item) => !content.message.contains(item))
// .toList();
// if (unmatchedItems.isNotEmpty) {
// for (int i = 0; i < unmatchedItems.length; i++) {
// String patternStr = unmatchedItems[i];
// spanChildren.addAll(
// [
// if (content.jumpUrl[patternStr]?['prefix_icon'] != null) ...[
// WidgetSpan(
// child: Image.network(
// content.jumpUrl[patternStr]['prefix_icon'],
// height: 19,
// color: Theme.of(context).colorScheme.primary,
// ),
// )
// ],
// TextSpan(
// text: content.jumpUrl[patternStr]['title'],
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// ),
// recognizer: TapGestureRecognizer()
// ..onTap = () {
// Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': patternStr,
// 'type': 'url',
// 'pageTitle': content.jumpUrl[patternStr]['title']
// },
// );
// },
// )
// ],
// );
// }
// }
// }
if (content.url.keys.isNotEmpty) {
List<String> unmatchedItems = content.url.keys
.toList()
.where((item) => !content.message.contains(item))
.toList();
if (unmatchedItems.isNotEmpty) {
for (int i = 0; i < unmatchedItems.length; i++) {
String patternStr = unmatchedItems[i];
spanChildren.addAll(
[
if (content.url[patternStr]?.hasPrefixIcon() == true) ...[
WidgetSpan(
child: Image.network(
content.url[patternStr]!.prefixIcon,
height: 19,
color: Theme.of(context).colorScheme.primary,
),
)
],
TextSpan(
text: content.url[patternStr]!.title,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
Get.toNamed(
'/webviewnew',
parameters: {
'url': patternStr,
'type': 'url',
'pageTitle': content.url[patternStr]!.title
},
);
},
)
],
);
}
}
}
// 图片渲染
// if (content.pictures.isNotEmpty) {
// spanChildren.add(const TextSpan(text: '\n'));
// spanChildren.add(
// WidgetSpan(
// child: LayoutBuilder(
// builder: (_, constraints) => image(
// constraints.maxWidth,
// (content.pictures as List)
// .map(
// (item) => ImageModel(
// width: item['img_width'],
// height: item['img_height'],
// url: item['img_src'],
// ),
// )
// .toList(),
// ),
// ),
// ),
// );
// }
if (content.pictures.isNotEmpty) {
spanChildren.add(const TextSpan(text: '\n'));
spanChildren.add(
WidgetSpan(
child: LayoutBuilder(
builder: (_, constraints) => image(
constraints.maxWidth,
content.pictures
.map(
(item) => ImageModel(
width: item.imgWidth,
height: item.imgHeight,
url: item.imgSrc,
),
)
.toList(),
),
),
),
);
}
// 笔记链接
// if (content.richText.isNotEmpty) {
// spanChildren.add(
// TextSpan(
// text: ' 笔记',
// style: TextStyle(
// color: Theme.of(context).colorScheme.primary,
// ),
// recognizer: TapGestureRecognizer()
// ..onTap = () => Get.toNamed(
// '/webviewnew',
// parameters: {
// 'url': content.richText['note']['click_url'],
// 'type': 'note',
// 'pageTitle': '笔记预览'
// },
// ),
// ),
// );
// }
if (content.hasRichText()) {
spanChildren.add(
TextSpan(
text: ' 笔记',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () => Get.toNamed(
'/webviewnew',
parameters: {
'url': content.richText.note.clickUrl,
'type': 'note',
'pageTitle': '笔记预览'
},
),
),
);
}
// spanChildren.add(TextSpan(text: matchMember));
return TextSpan(children: spanChildren);
}
@@ -1005,7 +1002,7 @@ class MorePanel extends StatelessWidget {
},
);
if (result == true && onDelete != null) {
onDelete!(item.id);
onDelete!(item.id.toInt());
}
break;
case 'copyAll':
@@ -1015,18 +1012,18 @@ class MorePanel extends StatelessWidget {
break;
case 'copyFreedom':
Get.back();
// showDialog(
// context: Get.context!,
// builder: (context) {
// return Dialog(
// child: Padding(
// padding:
// const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
// child: SelectableText(message),
// ),
// );
// },
// );
showDialog(
context: Get.context!,
builder: (context) {
return Dialog(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: SelectableText(message),
),
);
},
);
break;
// case 'block':
// SmartDialog.showToast('加入黑名单');
@@ -1075,7 +1072,7 @@ class MorePanel extends StatelessWidget {
SmartDialog.showToast('删除成功');
// Get.back();
if (onDelete != null) {
onDelete!(item.id);
onDelete!(item.id.toInt());
}
} else {
SmartDialog.showToast('删除失败, ${result["msg"]}');

View File

@@ -4,7 +4,6 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:PiliPalaX/http/reply.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/models/video/reply/item.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:fixnum/fixnum.dart' as $fixnum;

View File

@@ -2,6 +2,8 @@ import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart'
as reply;
import 'package:PiliPalaX/http/msg.dart';
import 'package:chat_bottom_container/chat_bottom_container.dart';
import 'package:flutter/material.dart';
@@ -24,7 +26,7 @@ class ReplyPage extends StatefulWidget {
final int? root;
final int? parent;
final ReplyType? replyType;
final ReplyItemModel? replyItem;
final reply.ReplyInfo? replyItem;
final String? savedReply;
final Function(String reply)? onSaveReply;
@@ -492,7 +494,7 @@ class _ReplyPageState extends State<ReplyPage>
root: widget.root!,
parent: widget.parent!,
message: widget.replyItem != null && widget.replyItem!.root != 0
? ' 回复 @${widget.replyItem!.member!.uname!} : $message'
? ' 回复 @${widget.replyItem!.member.name} : $message'
: message,
pictures: pictures,
);

View File

@@ -4,7 +4,6 @@ import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/http/reply.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/models/video/reply/item.dart';
class VideoReplyReplyController extends CommonController {
VideoReplyReplyController(this.aid, this.rpid, this.replyType);

View File

@@ -1,5 +1,4 @@
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pbenum.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/video/detail/reply/view.dart'
show MySliverPersistentHeaderDelegate;
@@ -11,8 +10,6 @@ import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_reply.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/models/common/reply_type.dart';
import 'package:PiliPalaX/models/video/reply/item.dart';
import 'package:PiliPalaX/pages/video/detail/reply/widgets/reply_item.dart';
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
import '../../../../utils/utils.dart';
@@ -122,7 +119,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
replyType: widget.replyType,
needDivider: false,
onReply: () {
// _onReply(widget.firstFloor!);
_onReply(widget.firstFloor!);
},
),
),
@@ -186,10 +183,10 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
);
}
void _onReply(ReplyItemModel? item) {
dynamic oid = item?.oid;
dynamic root = item?.rpid;
dynamic parent = item?.rpid;
void _onReply(ReplyInfo? item) {
dynamic oid = item?.oid.toInt();
dynamic root = item?.id.toInt();
dynamic parent = item?.id.toInt();
dynamic key = oid + root + parent;
Navigator.of(context)
.push(
@@ -224,13 +221,14 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
),
)
.then((value) {
// 完成评论,数据添加
if (value != null && value['data'] != null) {
// 完成评论,数据添加 // TODO: data cast
if (value != null && value['data'] is ReplyInfo) {
_savedReplies[key] = null;
List list = _videoReplyReplyController.loadingState.value is Success
? (_videoReplyReplyController.loadingState.value as Success)
.response
: [];
List<ReplyInfo> list =
_videoReplyReplyController.loadingState.value is Success
? (_videoReplyReplyController.loadingState.value as Success)
.response
: <ReplyInfo>[];
list.add(value['data']);
_videoReplyReplyController.loadingState.value =
LoadingState.success(list);
@@ -252,7 +250,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
replyType: widget.replyType,
needDivider: false,
onReply: () {
// _onReply(_videoReplyReplyController.root);
_onReply(_videoReplyReplyController.root);
},
),
),
@@ -297,8 +295,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
List list = (_videoReplyReplyController
.loadingState.value as Success)
.response;
list =
list.where((item) => item.rpid != rpid).toList();
list = list.where((item) => item.id != rpid).toList();
_videoReplyReplyController.loadingState.value =
LoadingState.success(list);
},