@@ -30,20 +30,6 @@ class SessionChatInputCard extends ConsumerStatefulWidget {
3030}
3131
3232class _SessionChatInputCardState extends ConsumerState <SessionChatInputCard > {
33- Set <String > _extractMentionedTables (String encoded) {
34- final segments = MentionSegmentSerializer .decode (encoded);
35- final tableNames = < String > {};
36-
37- // 只取“真正的 mention token”
38- for (final s in segments) {
39- if (s is MentionSegment ) {
40- tableNames.add (s.label);
41- }
42- }
43-
44- return tableNames;
45- }
46-
4733 MetaDataNode ? _findSchemaNode (SessionAIChatModel chatModel) {
4834 if (chatModel.metadata == null || chatModel.currentSchema == null ) return null ;
4935 final root = MetaDataNode (MetaType .instance, "" , items: chatModel.metadata! .metadata);
@@ -87,13 +73,11 @@ class _SessionChatInputCardState extends ConsumerState<SessionChatInputCard> {
8773
8874 Future <void > _sendMessage (AIChatId chatId, SessionAIChatModel chatModel) async {
8975 final chatInputController = SessionController .sessionController (chatModel.sessionId).chatInputController;
90- final encoded = chatInputController.text.trim ();
91- final segments = MentionSegmentSerializer .decode (encoded);
92- final text = segments.map ((s) => s.toDisplayText ()).join ().trim ();
76+ final text = chatInputController.displayText;
9377 chatInputController.clear ();
9478
9579 // 如果用户通过 @ 提及了表,则把表结构信息放到 ref 里
96- final mentionedTables = _extractMentionedTables (encoded );
80+ final mentionedTables = chatInputController.segments. whereType < MentionSegment >(). map ((s) => s.label). toList ( );
9781 final refText = _buildTableRef (chatModel, mentionedTables);
9882
9983 // 调用AIChatService的chat方法
@@ -325,112 +309,6 @@ class ChatInputFieldWidget extends ConsumerStatefulWidget {
325309}
326310
327311class _ChatInputFieldWidgetState extends ConsumerState <ChatInputFieldWidget > {
328- late final MentionTextEditingController _controller;
329- late final SessionController _sessionController;
330- late final VoidCallback _syncFromMention;
331- late final VoidCallback _syncFromSession;
332- bool _syncing = false ;
333-
334- @override
335- void initState () {
336- super .initState ();
337- _sessionController = SessionController .sessionController (widget.model.sessionId);
338- final stored = _sessionController.chatInputController.text;
339- final looksEncoded = stored.contains (MentionSegmentSerializer .mentionEndChar);
340- _controller = MentionTextEditingController (
341- text: looksEncoded ? null : stored,
342- encodedString: looksEncoded ? stored : null ,
343- mentionBuilderV2: _buildMentionWidget,
344- );
345-
346- _syncFromMention = () {
347- if (_syncing) return ;
348- _syncing = true ;
349- _sessionController.chatInputController.text = _controller.toEncodedString ();
350- _syncing = false ;
351- };
352- _syncFromSession = () {
353- if (_syncing) return ;
354- _syncing = true ;
355- final encoded = _sessionController.chatInputController.text;
356- if (encoded != _controller.toEncodedString ()) {
357- _controller.loadFromEncodedString (encoded);
358- }
359- _syncing = false ;
360- };
361-
362- _controller.addListener (_syncFromMention);
363- _sessionController.chatInputController.addListener (_syncFromSession);
364-
365- // 初始化时确保 session 保存的是 encodedString
366- _syncFromMention ();
367- }
368-
369- @override
370- void dispose () {
371- _controller.removeListener (_syncFromMention);
372- _sessionController.chatInputController.removeListener (_syncFromSession);
373- _controller.dispose ();
374- super .dispose ();
375- }
376-
377- Widget _buildMentionWidget (
378- BuildContext context,
379- MentionSegment segment,
380- TextStyle baseStyle,
381- bool hovering,
382- VoidCallback onDelete,
383- ) {
384- final colorScheme = Theme .of (context).colorScheme;
385- final cardBg = colorScheme.primaryContainer;
386- final cardFg = colorScheme.onSurface;
387- final fontSize = baseStyle.fontSize ?? 14 ;
388- // 让 token 的高度尽量贴近 TextField 的行高(selection 背景高度也会更一致)。
389- final heightFactor = baseStyle.height ?? 1.0 ;
390- final tokenHeight = fontSize * heightFactor;
391- final labelStyle = baseStyle.copyWith (color: cardFg, height: heightFactor);
392- return Container (
393- key: ValueKey ('table_mention_${segment .label }' ),
394- padding: const EdgeInsets .symmetric (horizontal: 6 ),
395- decoration: BoxDecoration (
396- color: cardBg,
397- borderRadius: BorderRadius .circular (5 ),
398- ),
399- child: SizedBox (
400- height: tokenHeight,
401- child: Row (
402- mainAxisSize: MainAxisSize .min,
403- crossAxisAlignment: CrossAxisAlignment .center,
404- children: [
405- if (hovering)
406- GestureDetector (
407- behavior: HitTestBehavior .opaque,
408- onTap: onDelete,
409- child: Icon (
410- Icons .close_rounded,
411- size: fontSize,
412- color: cardFg,
413- ),
414- )
415- else
416- HugeIcon (
417- icon: HugeIcons .strokeRoundedTable,
418- size: fontSize,
419- color: cardFg,
420- ),
421- const SizedBox (width: 4 ),
422- Center (
423- child: Text (
424- segment.label,
425- style: labelStyle,
426- ),
427- ),
428- ],
429- ),
430- ),
431- );
432- }
433-
434312 List <String > _getTableNames () {
435313 if (widget.model.metadata == null || widget.model.currentSchema == null ) {
436314 return [];
@@ -525,9 +403,10 @@ class _ChatInputFieldWidgetState extends ConsumerState<ChatInputFieldWidget> {
525403
526404 @override
527405 Widget build (BuildContext context) {
406+ final controller = SessionController .sessionController (widget.model.sessionId).chatInputController;
528407 final tokenBg = Theme .of (context).colorScheme.primaryContainer;
529408 return MentionTextField (
530- controller: _controller ,
409+ controller: controller ,
531410 style: Theme .of (context).textTheme.bodyMedium,
532411 textAlignVertical: TextAlignVertical .center,
533412 minLines: 1 ,
@@ -545,7 +424,7 @@ class _ChatInputFieldWidgetState extends ConsumerState<ChatInputFieldWidget> {
545424 mentionItemBuilder: _mentionItemBuilder,
546425 onSubmitted: (_) {
547426 widget.onSubmitted? .call ();
548- _controller. loadFromEncodedString ( '' );
427+ controller. clear ( );
549428 },
550429 );
551430 }
0 commit comments