Files
llm_chat/lib/widgets/chat_input.dart
2025-12-30 01:06:42 +08:00

89 lines
2.3 KiB
Dart

import 'package:fluent_ui/fluent_ui.dart';
class ChatInput extends StatefulWidget {
final Function(String) onSend;
final bool enabled;
const ChatInput({super.key, required this.onSend, this.enabled = true});
@override
State<ChatInput> createState() => _ChatInputState();
}
class _ChatInputState extends State<ChatInput> {
final TextEditingController _controller = TextEditingController();
final FocusNode _focusNode = FocusNode();
bool _hasContent = false;
@override
void initState() {
super.initState();
_controller.addListener(_onTextChanged);
}
void _onTextChanged() {
final hasContent = _controller.text.trim().isNotEmpty;
if (hasContent != _hasContent) {
setState(() {
_hasContent = hasContent;
});
}
}
void _sendMessage() {
if (_controller.text.trim().isNotEmpty && widget.enabled) {
widget.onSend(_controller.text.trim());
_controller.clear();
_focusNode.requestFocus();
}
}
@override
void dispose() {
_controller.dispose();
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final theme = FluentTheme.of(context);
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: theme.scaffoldBackgroundColor,
border: Border(
top: BorderSide(color: theme.resources.dividerStrokeColorDefault),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 150),
child: TextBox(
controller: _controller,
focusNode: _focusNode,
enabled: widget.enabled,
maxLines: null,
placeholder: 'Type a message...',
onSubmitted: (_) => _sendMessage(),
),
),
),
const SizedBox(width: 12),
FilledButton(
onPressed: _hasContent && widget.enabled ? _sendMessage : null,
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Icon(FluentIcons.send, size: 16),
),
),
],
),
);
}
}