import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import '../models/message.dart'; class MessageBubble extends StatelessWidget { final Message message; final bool showAvatar; const MessageBubble({ super.key, required this.message, this.showAvatar = true, }); @override Widget build(BuildContext context) { final theme = FluentTheme.of(context); return Padding( padding: const EdgeInsets.only(bottom: 16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: message.isUser ? MainAxisAlignment.end : MainAxisAlignment.start, children: [ if (!message.isUser && showAvatar) ...[ _buildAiAvatar(theme), const SizedBox(width: 12), ], Flexible(child: _buildMessageContent(context, theme)), if (message.isUser && showAvatar) ...[ const SizedBox(width: 12), _buildUserAvatar(theme), ], ], ), ); } Widget _buildAiAvatar(FluentThemeData theme) { return Container( width: 36, height: 36, decoration: BoxDecoration( color: theme.accentColor, borderRadius: BorderRadius.circular(8), ), child: const Icon(FluentIcons.robot, color: Colors.white, size: 18), ); } Widget _buildUserAvatar(FluentThemeData theme) { return Container( width: 36, height: 36, decoration: BoxDecoration( color: theme.accentColor.light, borderRadius: BorderRadius.circular(8), ), child: const Icon(FluentIcons.contact, color: Colors.white, size: 18), ); } Widget _buildMessageContent(BuildContext context, FluentThemeData theme) { if (message.isUser) { return Container( constraints: const BoxConstraints(maxWidth: 600), child: Card( backgroundColor: theme.accentColor, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Text( message.content, style: const TextStyle(color: Colors.white), ), ), ); } else { return Container( constraints: const BoxConstraints(maxWidth: 600), child: Card( padding: const EdgeInsets.all(12), child: MarkdownBody( data: message.content, selectable: true, styleSheet: MarkdownStyleSheet( p: theme.typography.body, h1: theme.typography.title, h2: theme.typography.subtitle, h3: theme.typography.bodyLarge, code: TextStyle( fontFamily: 'Consolas', fontSize: 13, backgroundColor: theme.cardColor, color: theme.accentColor, ), codeblockDecoration: BoxDecoration( color: theme.cardColor, borderRadius: BorderRadius.circular(4), ), blockquote: TextStyle( color: theme.typography.body?.color?.withAlpha(180), fontStyle: FontStyle.italic, ), blockquoteDecoration: BoxDecoration( border: Border( left: BorderSide(color: theme.accentColor, width: 3), ), ), tableHead: theme.typography.bodyStrong, tableBody: theme.typography.body, tableBorder: TableBorder.all( color: theme.resources.dividerStrokeColorDefault, ), tableCellsPadding: const EdgeInsets.all(8), strong: theme.typography.bodyStrong, em: TextStyle( fontStyle: FontStyle.italic, color: theme.typography.body?.color?.withAlpha(200), ), ), ), ), ); } } }