首次提交:初始化项目
This commit is contained in:
128
lib/widgets/message_bubble.dart
Normal file
128
lib/widgets/message_bubble.dart
Normal file
@@ -0,0 +1,128 @@
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user