import 'dart:convert'; import 'package:apidash/consts.dart'; import 'package:apidash/services/agentic_services/agent_caller.dart'; import 'package:apidash/widgets/widget_sending.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:genai/agentic_engine/blueprint.dart'; import 'package:stac/stac.dart' as stac; import '../services/agentic_services/agents/agents.dart'; void showCustomDialog(BuildContext context, String content) { showDialog( context: context, builder: (BuildContext context) { return Dialog( backgroundColor: Color.fromARGB(255, 16, 20, 24), // Dark background shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), child: DialogContents( content: content, ), ); }, ); } class DialogContents extends ConsumerStatefulWidget { final String content; const DialogContents({ super.key, required this.content, }); @override ConsumerState createState() => _DialogContentsState(); } class _DialogContentsState extends ConsumerState { int index = 0; TextEditingController controller = TextEditingController(); String generatedSDUI = '{}'; Future generateSDUICode(String apiResponse) async { setState(() { index = 1; //Induce Loading }); //STEP 1: RESPONSE_ANALYSER (call the Semantic Analysis & IRGen Bots in parallel) final step1Res = await Future.wait([ APIDashAgentCaller.instance.call( ResponseSemanticAnalyser(), ref: ref, input: AgentInputs(query: apiResponse), ), APIDashAgentCaller.instance.call( IntermediateRepresentationGen(), ref: ref, input: AgentInputs(variables: { 'VAR_API_RESPONSE': apiResponse, }), ), ]); final SA = step1Res[0]?['SEMANTIC_ANALYSIS']; final IR = step1Res[1]?['INTERMEDIATE_REPRESENTATION']; print("Semantic Analysis: $SA"); print("Intermediate Representation: $IR"); //STEP 2: STAC_GEN (Generate the SDUI Code) final sduiCode = await APIDashAgentCaller.instance.call( StacGenBot(), ref: ref, input: AgentInputs(variables: { 'VAR_RAW_API_RESPONSE': apiResponse, 'VAR_INTERMEDIATE_REPR': IR, 'VAR_SEMANTIC_ANALYSIS': SA, }), ); return sduiCode?['STAC']?.toString() ?? ""; } @override Widget build(BuildContext context) { return IndexedStack( index: index, children: [ FrameWorkSelectorPage( content: widget.content, onNext: (apiResponse, targetLanguage) async { print("Generating SDUI Code"); final sdui = await generateSDUICode(apiResponse); setState(() { index = 2; generatedSDUI = sdui; }); }, ), SizedBox( width: MediaQuery.of(context).size.width * 0.6, child: Center( child: Padding( padding: const EdgeInsets.only(top: 40.0), child: GestureDetector( onTap: () { // setState(() { // index = 2; // }); }, child: Container( height: 500, child: SendingWidget( startSendingTime: DateTime.now(), ), ), ), ), ), ), SDUIPreviewPage( onNext: () {}, sduiCode: generatedSDUI, ) ], ); } } class FrameWorkSelectorPage extends StatefulWidget { final String content; final Function(String, String) onNext; const FrameWorkSelectorPage( {super.key, required this.content, required this.onNext}); @override State createState() => _FrameWorkSelectorPageState(); } class _FrameWorkSelectorPageState extends State { String? selectedFramework; TextEditingController controller = TextEditingController(); @override void initState() { controller.text = widget.content; super.initState(); } @override Widget build(BuildContext context) { final textContainerdecoration = BoxDecoration( color: Color.alphaBlend( (Theme.of(context).brightness == Brightness.dark ? Theme.of(context).colorScheme.onPrimaryContainer : Theme.of(context).colorScheme.primaryContainer) .withOpacity(kForegroundOpacity), Theme.of(context).colorScheme.surface), border: Border.all( color: Theme.of(context).colorScheme.surfaceContainerHighest), borderRadius: kBorderRadius8, ); return Container( width: MediaQuery.of(context).size.width * 0.6, // Large dialog padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Container( width: double.maxFinite, padding: kP8, decoration: textContainerdecoration, child: SingleChildScrollView( child: TextField( controller: controller, maxLines: null, style: kCodeStyle, ), ), ), ), kVSpacer20, // Text( // "Select Framework", // style: TextStyle( // color: Colors.white, // fontSize: 18, // fontWeight: FontWeight.bold, // ), // ), // SizedBox(height: 10), // DropdownButtonFormField( // dropdownColor: Color(0xFF2D2D2D), // decoration: InputDecoration( // filled: true, // fillColor: Color(0xFF2D2D2D), // border: OutlineInputBorder( // borderRadius: BorderRadius.circular(8.0), // ), // ), // value: selectedFramework, // items: ["Flutter", "ReactJS"].map((String value) { // return DropdownMenuItem( // value: value, // child: Text( // value, // style: TextStyle(color: Colors.white), // ), // ); // }).toList(), // onChanged: (newValue) { // selectedFramework = newValue; // setState(() {}); // }, // ), // kVSpacer20, Align( alignment: Alignment.centerRight, child: FilledButton.tonalIcon( style: FilledButton.styleFrom( padding: kPh12, minimumSize: const Size(44, 44), ), onPressed: () { widget.onNext(controller.value.text, "FLUTTER"); }, icon: Icon( Icons.generating_tokens, ), label: const SizedBox( child: Text( kLabelGenerateUI, ), ), ), ), ], ), ); } } class SDUIPreviewPage extends ConsumerStatefulWidget { final String sduiCode; final Function() onNext; const SDUIPreviewPage( {super.key, required this.onNext, required this.sduiCode}); @override ConsumerState createState() => _SDUIPreviewPageState(); } class _SDUIPreviewPageState extends ConsumerState { bool exportingCode = false; @override Widget build(BuildContext context) { return Container( width: MediaQuery.of(context).size.width * 0.6, // Large dialog padding: EdgeInsets.all(20), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Generated Component", style: TextStyle( fontSize: 20, ), ), kVSpacer20, Expanded( child: Center( child: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( border: Border.all(color: Colors.white), ), child: widget.sduiCode == '{}' ? SizedBox() : StacRenderer( stacRepresentation: widget.sduiCode, ), ), ), ), kVSpacer20, if (!exportingCode) ...[ Container( width: double.infinity, decoration: BoxDecoration( color: Colors.black, // Dark background borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.grey, // Border color width: 1, ), ), child: TextField( maxLines: 3, // Makes the text box taller style: TextStyle(color: Colors.white), // White text decoration: InputDecoration( hintText: 'Any Modifications?', hintStyle: TextStyle(color: Colors.grey), // Grey hint text border: InputBorder.none, // Removes the default border contentPadding: EdgeInsets.all(16), // Padding inside the box ), ), ), kVSpacer20, ], Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Align( alignment: Alignment.centerRight, child: (exportingCode) ? Container( child: CircularProgressIndicator( strokeWidth: 1, ), margin: EdgeInsets.only(right: 10), ) : FilledButton.tonalIcon( style: FilledButton.styleFrom( padding: kPh12, minimumSize: const Size(44, 44), ), onPressed: () async { setState(() { exportingCode = true; }); final ans = await APIDashAgentCaller.instance.call( StacToFlutterBot(), ref: ref, input: AgentInputs( variables: {'VAR_CODE': widget.sduiCode}), ); final exportedCode = ans['CODE']; Clipboard.setData(ClipboardData(text: ans['CODE'])); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Copied to clipboard!"))); setState(() { exportingCode = false; }); }, icon: Icon( Icons.download, ), label: const SizedBox( child: Text( "Export Code", ), ), ), ), kHSpacer10, if (!exportingCode) Align( alignment: Alignment.centerRight, child: FilledButton.tonalIcon( style: FilledButton.styleFrom( padding: kPh12, minimumSize: const Size(44, 44), ), onPressed: () { widget.onNext(); }, icon: Icon( Icons.generating_tokens, ), label: const SizedBox( child: Text( "Make Modifications", ), ), ), ), ], ), ], ), ); } } class StacRenderer extends StatelessWidget { final String stacRepresentation; const StacRenderer({super.key, required this.stacRepresentation}); @override Widget build(BuildContext context) { return stac.StacApp( title: 'Component Preview', homeBuilder: (context) => Material( child: stac.Stac.fromJson(jsonDecode(stacRepresentation), context), ), ); } }