mirror of
https://github.com/foss42/apidash.git
synced 2025-12-01 18:28:25 +08:00
feat: implement scroll controller to scroll to the bottom
This commit is contained in:
@@ -18,6 +18,7 @@ class ChatScreen extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
class _ChatScreenState extends ConsumerState<ChatScreen> {
|
class _ChatScreenState extends ConsumerState<ChatScreen> {
|
||||||
final TextEditingController _textController = TextEditingController();
|
final TextEditingController _textController = TextEditingController();
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
bool _showTaskSuggestions = false;
|
bool _showTaskSuggestions = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -34,12 +35,36 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_textController.dispose();
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _scrollToBottom() {
|
||||||
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (_scrollController.hasClients) {
|
||||||
|
_scrollController.animateTo(
|
||||||
|
_scrollController.position.maxScrollExtent,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ref.listen(chatViewmodelProvider, (prev, next) {
|
ref.listen(chatViewmodelProvider, (prev, next) {
|
||||||
if (next.isGenerating) {
|
if (next.isGenerating) {
|
||||||
_showTaskSuggestions = false;
|
_showTaskSuggestions = false;
|
||||||
}
|
}
|
||||||
|
// Scroll to bottom when new message is added or streaming updates
|
||||||
|
if (prev?.currentStreamingResponse != next.currentStreamingResponse ||
|
||||||
|
(prev != null && prev.isGenerating && !next.isGenerating)) {
|
||||||
|
_scrollToBottom();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -54,23 +79,28 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
|||||||
if (msgs.isEmpty && !state.isGenerating) {
|
if (msgs.isEmpty && !state.isGenerating) {
|
||||||
return const Center(child: Text('Ask me anything!'));
|
return const Center(child: Text('Ask me anything!'));
|
||||||
}
|
}
|
||||||
return ListView.builder(
|
return Scrollbar(
|
||||||
itemCount: msgs.length + (state.isGenerating ? 1 : 0),
|
controller: _scrollController,
|
||||||
padding: const EdgeInsets.all(16.0),
|
thumbVisibility: true,
|
||||||
itemBuilder: (context, index) {
|
child: ListView.builder(
|
||||||
if (state.isGenerating && index == msgs.length) {
|
controller: _scrollController,
|
||||||
|
itemCount: msgs.length + (state.isGenerating ? 1 : 0),
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (state.isGenerating && index == msgs.length) {
|
||||||
|
return ChatBubble(
|
||||||
|
message: state.currentStreamingResponse,
|
||||||
|
role: MessageRole.system,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
final message = msgs[index];
|
||||||
return ChatBubble(
|
return ChatBubble(
|
||||||
message: state.currentStreamingResponse,
|
message: message.content,
|
||||||
role: MessageRole.system,
|
role: message.role,
|
||||||
|
actions: message.actions,
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
final message = msgs[index];
|
),
|
||||||
return ChatBubble(
|
|
||||||
message: message.content,
|
|
||||||
role: message.role,
|
|
||||||
actions: message.actions,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -80,7 +110,10 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
|||||||
height: 5,
|
height: 5,
|
||||||
thickness: 6,
|
thickness: 6,
|
||||||
),
|
),
|
||||||
if (_showTaskSuggestions) DashbotTaskButtons(),
|
if (_showTaskSuggestions)
|
||||||
|
DashbotTaskButtons(
|
||||||
|
onTaskSelected: _scrollToBottom,
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -128,6 +161,7 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
|||||||
text: text,
|
text: text,
|
||||||
type: ChatMessageType.general,
|
type: ChatMessageType.general,
|
||||||
);
|
);
|
||||||
|
_scrollToBottom();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -145,6 +179,7 @@ class _ChatScreenState extends ConsumerState<ChatScreen> {
|
|||||||
text: text,
|
text: text,
|
||||||
type: ChatMessageType.general,
|
type: ChatMessageType.general,
|
||||||
);
|
);
|
||||||
|
_scrollToBottom();
|
||||||
},
|
},
|
||||||
tooltip: 'Send message',
|
tooltip: 'Send message',
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import '../../../home/view/widgets/home_screen_task_button.dart';
|
|||||||
import '../../../../core/providers/dashbot_window_notifier.dart';
|
import '../../../../core/providers/dashbot_window_notifier.dart';
|
||||||
|
|
||||||
class DashbotTaskButtons extends ConsumerWidget {
|
class DashbotTaskButtons extends ConsumerWidget {
|
||||||
const DashbotTaskButtons({super.key});
|
final VoidCallback? onTaskSelected;
|
||||||
|
|
||||||
|
const DashbotTaskButtons({super.key, this.onTaskSelected});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@@ -37,42 +39,49 @@ class DashbotTaskButtons extends ConsumerWidget {
|
|||||||
label: '🔎 Explain me this response',
|
label: '🔎 Explain me this response',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.explainResponse);
|
vm.sendTaskMessage(ChatMessageType.explainResponse);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
label: '🐞 Help me debug this error',
|
label: '🐞 Help me debug this error',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.debugError);
|
vm.sendTaskMessage(ChatMessageType.debugError);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
label: '📄 Generate documentation',
|
label: '📄 Generate documentation',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.generateDoc);
|
vm.sendTaskMessage(ChatMessageType.generateDoc);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
label: '📝 Generate Tests',
|
label: '📝 Generate Tests',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.generateTest);
|
vm.sendTaskMessage(ChatMessageType.generateTest);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
label: '🧩 Generate Code',
|
label: '🧩 Generate Code',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.generateCode);
|
vm.sendTaskMessage(ChatMessageType.generateCode);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
label: '📥 Import cURL',
|
label: '📥 Import cURL',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.importCurl);
|
vm.sendTaskMessage(ChatMessageType.importCurl);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
label: '📄 Import OpenAPI',
|
label: '📄 Import OpenAPI',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
vm.sendTaskMessage(ChatMessageType.importOpenApi);
|
vm.sendTaskMessage(ChatMessageType.importOpenApi);
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
@@ -83,6 +92,7 @@ class DashbotTaskButtons extends ConsumerWidget {
|
|||||||
notifier.hide();
|
notifier.hide();
|
||||||
await GenerateToolDialog.show(context, ref);
|
await GenerateToolDialog.show(context, ref);
|
||||||
notifier.show();
|
notifier.show();
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
HomeScreenTaskButton(
|
HomeScreenTaskButton(
|
||||||
@@ -107,6 +117,7 @@ class DashbotTaskButtons extends ConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
notifier.show();
|
notifier.show();
|
||||||
|
onTaskSelected?.call();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user