opt msg item

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-24 10:48:01 +08:00
parent 5bd6b38908
commit da56c66168
2 changed files with 145 additions and 124 deletions

View File

@@ -147,7 +147,7 @@ class _WhisperDetailPageState
shrinkWrap: true,
reverse: true,
itemCount: response!.length,
padding: const EdgeInsets.all(12),
padding: const EdgeInsets.all(14),
physics: const AlwaysScrollableScrollPhysics(
parent: ClampingScrollPhysics(),
),

View File

@@ -1,11 +1,13 @@
import 'dart:convert';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/grpc/bilibili/im/interfaces/v1.pb.dart'
show EmotionInfo;
import 'package:PiliPlus/grpc/bilibili/im/type.pb.dart' show Msg, MsgType;
import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/models/common/badge_type.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart';
import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
@@ -39,7 +41,8 @@ class ChatItem extends StatelessWidget {
Widget build(BuildContext context) {
bool isPic = item.msgType == MsgType.EN_MSG_TYPE_PIC.value; // 图片
bool isRevoke = item.msgType == MsgType.EN_MSG_TYPE_DRAW_BACK.value; // 撤回消息
bool isSystem = item.msgType == MsgType.EN_MSG_TYPE_TIP_MESSAGE.value ||
bool isSystem = item.msgType == MsgType.EN_MSG_TYPE_VIDEO_CARD.value ||
item.msgType == MsgType.EN_MSG_TYPE_TIP_MESSAGE.value ||
item.msgType == MsgType.EN_MSG_TYPE_NOTIFY_MSG.value ||
item.msgType == MsgType.EN_MSG_TYPE_PICTURE_CARD.value ||
item.msgType == 16;
@@ -52,80 +55,81 @@ class ChatItem extends StatelessWidget {
return isRevoke
? const SizedBox.shrink()
: isSystem
? messageContent(
context: context,
theme: theme,
content: content,
textColor: textColor,
)
: GestureDetector(
onLongPress: () {
Feedback.forLongPress(context);
onLongPress?.call();
},
child: Row(
mainAxisAlignment:
isOwner ? MainAxisAlignment.end : MainAxisAlignment.start,
children: [
Container(
constraints: const BoxConstraints(maxWidth: 300.0),
decoration: BoxDecoration(
color: isOwner
? theme.colorScheme.secondaryContainer
: theme.colorScheme.onInverseSurface,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(16),
topRight: const Radius.circular(16),
bottomLeft: Radius.circular(isOwner ? 16 : 6),
bottomRight: Radius.circular(isOwner ? 6 : 16),
),
),
padding: EdgeInsets.only(
top: 8,
bottom: 6,
left: isPic ? 8 : 12,
right: isPic ? 8 : 12,
),
child: Column(
crossAxisAlignment: isOwner
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 6, bottom: 18),
child: Text(
Utils.dateFormat(item.timestamp.toInt()),
textAlign: TextAlign.center,
style: TextStyle(color: theme.colorScheme.outline),
),
),
isSystem
? messageContent(
context: context,
theme: theme,
content: content,
textColor: textColor,
)
: GestureDetector(
onLongPress: onLongPress == null
? null
: () {
Feedback.forLongPress(context);
onLongPress!();
},
child: Row(
mainAxisAlignment: isOwner
? MainAxisAlignment.end
: MainAxisAlignment.start,
children: [
messageContent(
context: context,
theme: theme,
content: content,
textColor: textColor,
),
SizedBox(height: isPic ? 7 : 2),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
Utils.dateFormat(item.timestamp.toInt()),
style: theme.textTheme.labelSmall!.copyWith(
color: isOwner
? theme.colorScheme.onSecondaryContainer
.withValues(alpha: 0.8)
: theme.colorScheme.onSurfaceVariant
.withValues(alpha: 0.8)),
Container(
constraints: const BoxConstraints(maxWidth: 300.0),
decoration: BoxDecoration(
color: isOwner
? theme.colorScheme.secondaryContainer
: theme.colorScheme.onInverseSurface,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(16),
topRight: const Radius.circular(16),
bottomLeft: Radius.circular(isOwner ? 16 : 6),
bottomRight: Radius.circular(isOwner ? 6 : 16),
),
if (item.msgStatus == 1)
Text(
' 已撤回',
style: theme.textTheme.labelSmall!.copyWith(
color: theme.colorScheme.onErrorContainer,
),
),
padding: EdgeInsets.only(
top: 8,
bottom: 6,
left: isPic ? 8 : 12,
right: isPic ? 8 : 12,
),
child: Column(
crossAxisAlignment: isOwner
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
children: [
messageContent(
context: context,
theme: theme,
content: content,
textColor: textColor,
),
],
)
SizedBox(height: isPic ? 7 : 2),
if (item.msgStatus == 1)
Text(
' 已撤回',
style: theme.textTheme.labelSmall!.copyWith(
color: theme.colorScheme.onErrorContainer,
),
),
],
),
),
],
),
),
],
),
);
],
);
}
Widget messageContent({
@@ -149,7 +153,7 @@ class ChatItem extends StatelessWidget {
case MsgType.EN_MSG_TYPE_SHARE_V2:
return msgTypeShareV2_7(content, textColor);
case MsgType.EN_MSG_TYPE_VIDEO_CARD:
return msgTypeVideoCard_11(content, textColor);
return msgTypeVideoCard_11(theme, content, textColor);
case MsgType.EN_MSG_TYPE_ARTICLE_CARD:
return msgTypeArticleCard_12(content, textColor);
case MsgType.EN_MSG_TYPE_COMMON_SHARE_CARD:
@@ -357,56 +361,78 @@ class ChatItem extends StatelessWidget {
);
}
Widget msgTypeVideoCard_11(content, Color textColor) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () async {
try {
SmartDialog.showLoading();
var bvid = content["bvid"];
final int cid = await SearchHttp.ab2c(bvid: bvid);
SmartDialog.dismiss();
PageUtils.toVideoPage(
'bvid=$bvid&cid=$cid',
arguments: {
'pic': content['thumb'],
'heroTag': Utils.makeHeroTag(bvid),
},
);
} catch (err) {
SmartDialog.dismiss();
SmartDialog.showToast(err.toString());
}
Widget msgTypeVideoCard_11(ThemeData theme, content, Color textColor) {
return Center(
child: Container(
clipBehavior: Clip.hardEdge,
constraints: const BoxConstraints(maxWidth: 400.0),
decoration: BoxDecoration(
borderRadius: StyleString.mdRadius,
color: theme.colorScheme.onInverseSurface,
),
child: LayoutBuilder(
builder: (_, constrains) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
try {
SmartDialog.showLoading();
var bvid = content["bvid"];
final int cid = await SearchHttp.ab2c(bvid: bvid);
SmartDialog.dismiss();
PageUtils.toVideoPage(
'bvid=$bvid&cid=$cid',
arguments: {
'pic': content['thumb'],
'heroTag': Utils.makeHeroTag(bvid),
},
);
} catch (err) {
SmartDialog.dismiss();
SmartDialog.showToast(err.toString());
}
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
type: ImageType.emote,
width: constrains.maxWidth,
height: constrains.maxWidth * 9 / 16,
src: content['cover'],
),
PBadge(
left: 6,
bottom: 6,
type: PBadgeType.gray,
text: content['times'] == 0
? '--:--'
: Utils.timeFormat(content['times']),
)
],
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Text(
content['times'] == 0 ? '内容已失效' : content['title'],
style: TextStyle(
letterSpacing: 0.6,
height: 1.5,
color: textColor,
fontWeight: FontWeight.bold,
),
),
),
],
),
);
},
child: NetworkImgLayer(
width: 220,
height: 220 * 9 / 16,
src: content['cover'],
),
),
const SizedBox(height: 6),
SelectableText(
content['title'],
style: TextStyle(
letterSpacing: 0.6,
height: 1.5,
color: textColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 1),
Text(
Utils.timeFormat(content['times']),
style: TextStyle(
letterSpacing: 0.6,
height: 1.5,
color: textColor.withValues(alpha: 0.6),
fontSize: 12,
),
),
],
),
);
}
@@ -620,11 +646,6 @@ class ChatItem extends StatelessWidget {
fontWeight: FontWeight.bold,
),
),
Text(
Utils.dateFormat(item.timestamp.toInt()),
style: theme.textTheme.labelSmall!
.copyWith(color: theme.colorScheme.outline),
),
Divider(color: theme.colorScheme.primary.withValues(alpha: 0.05)),
SelectableText(content['text']),
if (modules?.isNotEmpty == true) ...[