11import 'package:flutter/material.dart' ;
2+ import 'package:flutter/services.dart' ;
23import 'package:lucide_icons_flutter/lucide_icons.dart' ;
34import 'package:starguide_flutter/config/constants.dart' ;
45
@@ -32,23 +33,28 @@ class _StarguideChatInputState extends State<StarguideChatInput> {
3233 final String hintText;
3334
3435 if (widget.numChatRequests >= kMaxChatRequests) {
35- hintText = 'Clear the chat to start a new conversation.' ;
36+ hintText = 'Clear the chat to start aR new conversation.' ;
3637 } else if (widget.numChatRequests == 0 ) {
3738 hintText = 'Ask me anything about Serverpod...' ;
3839 } else {
3940 hintText = 'Ask a follow-up question...' ;
4041 }
4142
4243 return Container (
43- padding:
44- const EdgeInsets .only (left: 12.0 , right: 8.0 , top: 8.0 , bottom: 8.0 ),
45- child: Column (
44+ padding: const EdgeInsets .only (
45+ left: 12.0 ,
46+ right: 8.0 ,
47+ ),
48+ child: Row (
49+ crossAxisAlignment: CrossAxisAlignment .end,
4650 children: [
47- Row (
48- children: [
49- Expanded (
51+ Expanded (
52+ child: KeyboardListener (
53+ focusNode: widget.focusNode,
54+ onKeyEvent: (event) => _handleKeyboardEvents (event),
55+ child: Container (
56+ constraints: BoxConstraints (maxHeight: 400.0 ),
5057 child: TextField (
51- focusNode: widget.focusNode,
5258 autofocus: true ,
5359 enabled: widget.numChatRequests < kMaxChatRequests,
5460 buildCounter: (
@@ -60,56 +66,76 @@ class _StarguideChatInputState extends State<StarguideChatInput> {
6066 return const SizedBox ();
6167 },
6268 maxLength: kMaxChatRequestLength,
63- maxLines: 1 ,
64- decoration: InputDecoration .collapsed (
69+ maxLines: null ,
70+ minLines: 1 ,
71+ keyboardType: TextInputType .multiline,
72+ textInputAction: TextInputAction .newline,
73+ textAlignVertical: TextAlignVertical .top,
74+ decoration: InputDecoration (
6575 hintText: hintText,
6676 hintStyle: TextStyle (color: theme.disabledColor),
77+ border: InputBorder .none,
6778 ),
6879 controller: widget.textController,
69- onSubmitted: (value) {
70- widget.onSend (widget.textController.text);
71- widget.textController.clear ();
72- widget.focusNode.requestFocus ();
73- },
7480 ),
7581 ),
76- if (widget.isGeneratingResponse)
77- Container (
78- padding: const EdgeInsets .all (10 ),
79- width: 40 ,
80- height: 40 ,
81- child: CircularProgressIndicator (
82- color: theme.colorScheme.primary,
83- ),
84- )
85- else
86- TextButton (
87- style: TextButton .styleFrom (
88- backgroundColor: widget.focusNode.hasFocus
89- ? theme.colorScheme.primary
90- : theme.dividerColor,
91- shape: RoundedRectangleBorder (
92- borderRadius: BorderRadius .circular (4 ),
82+ ),
83+ ),
84+ Padding (
85+ padding: const EdgeInsets .symmetric (vertical: 8 ),
86+ child: Column (
87+ children: [
88+ if (widget.isGeneratingResponse)
89+ Container (
90+ padding: const EdgeInsets .all (10 ),
91+ width: 40 ,
92+ height: 40 ,
93+ child: CircularProgressIndicator (
94+ color: theme.colorScheme.primary,
95+ ),
96+ )
97+ else
98+ TextButton (
99+ style: TextButton .styleFrom (
100+ backgroundColor: widget.focusNode.hasFocus
101+ ? theme.colorScheme.primary
102+ : theme.dividerColor,
103+ shape: RoundedRectangleBorder (
104+ borderRadius: BorderRadius .circular (4 ),
105+ ),
106+ padding: const EdgeInsets .all (4 ),
107+ minimumSize: const Size (48 , 48 ),
108+ ),
109+ onPressed: widget.enabled ? _handleSubmit : null ,
110+ child: const Icon (
111+ LucideIcons .rocket300,
112+ size: 20 ,
113+ color: Colors .white,
93114 ),
94- padding: const EdgeInsets .all (4 ),
95- minimumSize: const Size (48 , 48 ),
96- ),
97- onPressed: widget.enabled
98- ? () {
99- widget.onSend (widget.textController.text);
100- widget.textController.clear ();
101- }
102- : null ,
103- child: const Icon (
104- LucideIcons .rocket300,
105- size: 20 ,
106- color: Colors .white,
107115 ),
108- ) ,
109- ] ,
110- ),
116+ ] ,
117+ ) ,
118+ )
111119 ],
112120 ),
113121 );
114122 }
115- }
123+
124+ void _handleKeyboardEvents (KeyEvent event) {
125+ if (event is KeyDownEvent ) {
126+ final isEnterPressed = event.logicalKey == LogicalKeyboardKey .enter;
127+ final isShiftPressed = HardwareKeyboard .instance.isShiftPressed;
128+
129+ if (isEnterPressed && ! isShiftPressed && widget.enabled) {
130+ _handleSubmit ();
131+ }
132+ }
133+ }
134+
135+ void _handleSubmit () {
136+ if (widget.textController.text.trim ().isNotEmpty) {
137+ widget.onSend (widget.textController.text);
138+ widget.textController.clear ();
139+ }
140+ }
141+ }
0 commit comments