// lib/dashbot/widgets/dashbot_widget.dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/dashbot/providers/dashbot_providers.dart'; import 'package:apidash/providers/providers.dart'; import 'chat_bubble.dart'; class DashBotWidget extends ConsumerStatefulWidget { const DashBotWidget({ super.key, }); @override ConsumerState createState() => _DashBotWidgetState(); } class _DashBotWidgetState extends ConsumerState { final TextEditingController _controller = TextEditingController(); late ScrollController _scrollController; bool _isLoading = false; @override void initState() { super.initState(); _scrollController = ScrollController(); } @override void dispose() { _scrollController.dispose(); _controller.dispose(); super.dispose(); } Future _sendMessage(String message) async { if (message.trim().isEmpty) return; final dashBotService = ref.read(dashBotServiceProvider); final requestModel = ref.read(selectedRequestModelProvider); final responseModel = requestModel?.httpResponseModel; setState(() => _isLoading = true); ref.read(chatMessagesProvider.notifier).addMessage({ 'role': 'user', 'message': message, }); try { final response = await dashBotService.handleRequest( message, requestModel, responseModel); ref.read(chatMessagesProvider.notifier).addMessage({ 'role': 'bot', 'message': response, }); } catch (error, stackTrace) { debugPrint('Error in _sendMessage: $error'); debugPrint('StackTrace: $stackTrace'); ref.read(chatMessagesProvider.notifier).addMessage({ 'role': 'bot', 'message': "Error: ${error.toString()}", }); } finally { setState(() => _isLoading = false); WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.animateTo( 0, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); }); } } @override Widget build(BuildContext context) { final messages = ref.watch(chatMessagesProvider); final requestModel = ref.read(selectedRequestModelProvider); final statusCode = requestModel?.httpResponseModel?.statusCode; final showDebugButton = statusCode != null && statusCode >= 400; return Container( height: 450, width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(12), boxShadow: const [ BoxShadow(color: Colors.black12, blurRadius: 8, offset: Offset(0, 4)) ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(context), const SizedBox(height: 12), _buildQuickActions(showDebugButton), const SizedBox(height: 12), Expanded(child: _buildChatArea(messages)), if (_isLoading) _buildLoadingIndicator(), const SizedBox(height: 10), _buildInputArea(context), ], ), ); } Widget _buildHeader(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('DashBot', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), IconButton( icon: const Icon(Icons.delete_sweep), tooltip: 'Clear Chat', onPressed: () => ref.read(chatMessagesProvider.notifier).clearMessages(), ), ], ); } Widget _buildQuickActions(bool showDebugButton) { return Wrap( spacing: 8, runSpacing: 8, children: [ ElevatedButton.icon( onPressed: () => _sendMessage("Explain API"), icon: const Icon(Icons.info_outline), label: const Text("Explain"), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), ), if (showDebugButton) ElevatedButton.icon( onPressed: () => _sendMessage("Debug API"), icon: const Icon(Icons.bug_report_outlined), label: const Text("Debug"), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), ), ), ], ); } Widget _buildChatArea(List> messages) { return ListView.builder( controller: _scrollController, reverse: true, itemCount: messages.length, itemBuilder: (context, index) { final message = messages.reversed.toList()[index]; return ChatBubble( message: message['message'], isUser: message['role'] == 'user', ); }, ); } Widget _buildLoadingIndicator() { return const Padding( padding: EdgeInsets.all(8.0), child: LinearProgressIndicator(), ); } Widget _buildInputArea(BuildContext context) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: Theme.of(context).colorScheme.surfaceContainer, ), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( children: [ Expanded( child: TextField( controller: _controller, decoration: const InputDecoration( hintText: 'Ask DashBot...', border: InputBorder.none, ), onSubmitted: _sendMessage, maxLines: 1, ), ), IconButton( icon: const Icon(Icons.send), onPressed: () => _sendMessage(_controller.text), ), ], ), ); } }