import "package:flutter/material.dart" as material hide Card; import "package:flutter_markdown/flutter_markdown.dart"; import "package:shadcn_flutter/shadcn_flutter.dart"; import "../../src/session/session_types.dart"; class MessageBubble extends StatelessWidget { const MessageBubble({required this.message}); final Message message; @override Widget build(BuildContext context) { final isUser = message.role == "user"; final isTool = message.role == "tool"; final isAssistant = message.role == "assistant"; final accentColor = isTool ? const Color(0xFF64748B) : const Color(0xFF94A3B8); return Align( alignment: isUser ? Alignment.centerRight : Alignment.centerLeft, child: Container( constraints: BoxConstraints( maxWidth: material.MediaQuery.of(context).size.width * 0.7, ), margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Card( child: Padding( padding: const EdgeInsets.all(12), child: material.Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( message.role, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: accentColor, ), ), const SizedBox(height: 4), if (isAssistant || isTool) MarkdownBody( data: isTool ? _buildToolMarkdown(message.content) : message.content, selectable: true, shrinkWrap: true, styleSheet: isTool ? _toolMarkdownStyleSheet(context) : null, ) else Text(message.content), ], ), ), ), ), ); } String _buildToolMarkdown(String content) { final lines = content.split("\n"); if (lines.isEmpty) { return "```text\n\n```"; } final title = lines.first.trim(); final body = lines.skip(1).join("\n").trimRight(); if (body.isEmpty) { return title; } return "$title\n\n```text\n$body\n```"; } MarkdownStyleSheet _toolMarkdownStyleSheet(BuildContext context) { final theme = Theme.of(context); return MarkdownStyleSheet.fromTheme(material.Theme.of(context)).copyWith( p: theme.typography.base.copyWith(height: 1.35), codeblockDecoration: BoxDecoration( color: theme.colorScheme.muted.withValues(alpha: 0.35), borderRadius: BorderRadius.circular(10), ), codeblockPadding: const EdgeInsets.all(12), code: theme.typography.base.copyWith( fontFamily: "monospace", height: 1.35, ), ); } }