flexible bubble

This commit is contained in:
Chen Li
2025-08-22 09:28:15 +08:00
parent 2f0e82fd69
commit f5116fb2ac
2 changed files with 42 additions and 72 deletions

View File

@@ -72,7 +72,7 @@ class _PartScreenState extends State<PartScreen> {
context.watch<MessageService>().messages.length;
double chatHeight;
if (messageCount <= 1) {
chatHeight = minHeight;
chatHeight = minHeight + 70;
} else {
final height = minHeight + (messageCount * 78);
chatHeight = height < maxHeight ? height : maxHeight;

View File

@@ -28,67 +28,46 @@ class _ChatBubbleState extends State<ChatBubble> {
@override
Widget build(BuildContext context) {
final isThinking = message.status == MessageStatus.thinking;
final content = Container(
constraints: const BoxConstraints(minWidth: 50),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
decoration: BoxDecoration(
color: message.isUser
? CommonUtil.commonColor
: Colors.white.withOpacity(0.12),
borderRadius: message.isUser
? const BorderRadius.only(
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
)
: const BorderRadius.only(
topRight: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: message.isUser
? _buildUserContent()
: _buildAssistantContent(isThinking),
);
// 用户气泡做宽度自适应处理
final wrappedContent = message.isUser
? ConstrainedBox(
constraints: const BoxConstraints(
maxWidth: double.infinity,
),
child: IntrinsicWidth(child: content),
)
: content;
return Align(
alignment: message.isUser ? Alignment.centerRight : Alignment.centerLeft,
child: Column(
crossAxisAlignment:
message.isUser ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Container(
constraints: const BoxConstraints(
minWidth: 50,
),
width: isThinking ? double.infinity : null,
child: isThinking
? Container(
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 12),
decoration: BoxDecoration(
color: message.isUser
? CommonUtil.commonColor
: Colors.white.withValues(alpha: 0.12),
borderRadius: message.isUser
? BorderRadius.only(
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
)
: BorderRadius.only(
topRight: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: _buildAssistantContent(isThinking),
)
: Container(
constraints: const BoxConstraints(
minWidth: 50,
),
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 12),
decoration: BoxDecoration(
color: message.isUser
? CommonUtil.commonColor
: Colors.white.withOpacity(0.12),
borderRadius: message.isUser
? BorderRadius.only(
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
)
: BorderRadius.only(
topRight: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
),
child: message.isUser
? _buildUserContent()
: _buildAssistantContent(isThinking),
),
),
],
children: [wrappedContent],
),
);
}
@@ -129,9 +108,7 @@ class _ChatBubbleState extends State<ChatBubble> {
case MessageStatus.listening:
case MessageStatus.recognizing:
case MessageStatus.thinking:
icon = RotatingImage(
imagePath: 'assets/images/thinking_circle.png'
);
icon = RotatingImage(imagePath: 'assets/images/thinking_circle.png');
color = Colors.white;
break;
case MessageStatus.executing:
@@ -146,11 +123,7 @@ class _ChatBubbleState extends State<ChatBubble> {
break;
case MessageStatus.completed:
case MessageStatus.success:
icon = Image.asset(
'assets/images/checked.png',
width: 20,
height: 20
);
icon = Image.asset('assets/images/checked.png', width: 20, height: 20);
color = Colors.white;
break;
case MessageStatus.failure:
@@ -274,8 +247,8 @@ class _ChatBubbleState extends State<ChatBubble> {
child: Divider(color: Colors.white, height: 1),
),
const SizedBox(height: 12),
SizedBox(
height: 24,
ConstrainedBox(
constraints: const BoxConstraints(minHeight: 24),
child: isThinking
? Row(
mainAxisAlignment: MainAxisAlignment.end,
@@ -328,11 +301,8 @@ class _ChatBubbleState extends State<ChatBubble> {
},
child: Padding(
padding: const EdgeInsets.only(left: 12),
child: Image.asset(
'assets/images/copy.png',
width: 22,
height: 22
),
child: Image.asset('assets/images/copy.png',
width: 22, height: 22),
),
),
InkWell(