diff --git a/lib/dashbot/features/chat/view/widgets/chat_bubble.dart b/lib/dashbot/features/chat/view/widgets/chat_bubble.dart index 457616f3..0a83920d 100644 --- a/lib/dashbot/features/chat/view/widgets/chat_bubble.dart +++ b/lib/dashbot/features/chat/view/widgets/chat_bubble.dart @@ -7,6 +7,7 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../viewmodel/chat_viewmodel.dart'; import '../../models/chat_models.dart'; +import 'common_languages_picker.dart'; class ChatBubble extends ConsumerWidget { final String message; @@ -107,7 +108,7 @@ class ChatBubble extends ConsumerWidget { if (role == MessageRole.system) ...[ if (action != null) ...[ const SizedBox(height: 4), - _buildActionButton(context, ref, action!), + _buildActionWidget(context, ref, action!), ], const SizedBox(height: 4), IconButton( @@ -125,9 +126,72 @@ class ChatBubble extends ConsumerWidget { ); } - Widget _buildActionButton( + Widget _buildActionWidget( BuildContext context, WidgetRef ref, ChatAction action) { final isTestAction = action.action == 'other' && action.target == 'test'; + final isCodeResult = action.action == 'other' && action.target == 'code'; + if (isCodeResult) { + final code = (action.value is String) ? action.value as String : ''; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Theme.of(context).colorScheme.outlineVariant, + ), + ), + child: SelectableText( + code.isEmpty ? '// No code returned' : code, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + fontFamily: 'monospace', + ), + ), + ), + const SizedBox(height: 6), + Row( + children: [ + TextButton.icon( + onPressed: () { + Clipboard.setData(ClipboardData(text: code)); + }, + icon: const Icon(Icons.copy_rounded, size: 16), + label: const Text('Copy code'), + ), + ], + ), + ], + ); + } + final isShowLanguages = + action.action == 'show_languages' && action.target == 'codegen'; + + if (isShowLanguages) { + final dynamic val = action.value; + final List langs = val is List + ? val.whereType().toList() + : const [ + 'JavaScript (fetch)', + 'Python (requests)', + 'Dart (http)', + 'Go (net/http)', + 'cURL', + ]; + return CommonLanguagesPicker( + languages: langs, + onSelected: (lang) { + final vm = ref.read(chatViewmodelProvider.notifier); + vm.sendMessage( + text: 'Please generate code in $lang', + type: ChatMessageType.generateCode, + ); + }, + ); + } return ElevatedButton.icon( onPressed: () async { diff --git a/lib/dashbot/features/chat/view/widgets/common_languages_picker.dart b/lib/dashbot/features/chat/view/widgets/common_languages_picker.dart new file mode 100644 index 00000000..63c374f8 --- /dev/null +++ b/lib/dashbot/features/chat/view/widgets/common_languages_picker.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +class CommonLanguageButton extends StatelessWidget { + const CommonLanguageButton({ + super.key, + required this.label, + required this.onPressed, + this.textAlign = TextAlign.center, + }); + + final String label; + final VoidCallback onPressed; + final TextAlign textAlign; + + @override + Widget build(BuildContext context) { + return TextButton( + onPressed: onPressed, + style: TextButton.styleFrom( + side: BorderSide( + color: Theme.of(context).colorScheme.primary, + ), + padding: const EdgeInsets.symmetric( + vertical: 0, + horizontal: 16, + ), + ), + child: Text( + label, + textAlign: textAlign, + ), + ); + } +} + +class CommonLanguagesPicker extends StatelessWidget { + const CommonLanguagesPicker({ + super.key, + required this.languages, + required this.onSelected, + }); + + final List languages; + final ValueChanged onSelected; + + @override + Widget build(BuildContext context) { + final langs = languages.length > 6 ? languages.take(6).toList() : languages; + return Wrap( + spacing: 8, + runSpacing: 8, + children: [ + for (final l in langs) + CommonLanguageButton( + label: l, + onPressed: () => onSelected(l), + ), + ], + ); + } +} diff --git a/lib/dashbot/features/home/view/pages/home_page.dart b/lib/dashbot/features/home/view/pages/home_page.dart index a0956c3f..fac8751e 100644 --- a/lib/dashbot/features/home/view/pages/home_page.dart +++ b/lib/dashbot/features/home/view/pages/home_page.dart @@ -93,6 +93,15 @@ class _DashbotHomePageState extends ConsumerState { ); }, ), + HomeScreenTaskButton( + label: "🧩 Generate Code", + onPressed: () { + Navigator.of(context).pushNamed( + DashbotRoutes.dashbotChat, + arguments: ChatMessageType.generateCode, + ); + }, + ), if (currentRequest?.httpResponseModel?.statusCode != null && currentRequest?.httpResponseModel?.statusCode == 200) ...[ HomeScreenTaskButton(