diff --git a/lib/console.dart b/lib/console.dart deleted file mode 100644 index 32ae30ce..00000000 --- a/lib/console.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter_highlighter/flutter_highlighter.dart'; -import 'package:flutter_highlighter/themes/github.dart'; -import 'package:get_it/get_it.dart'; -import 'package:sail_ui/widgets/core/sail_text.dart'; -import 'package:sidesail/logger.dart'; -import 'package:sidesail/rpc/rpc_sidechain.dart'; - -class RpcWidget extends StatefulWidget { - const RpcWidget({super.key}); - - @override - RpcWidgetState createState() => RpcWidgetState(); -} - -class RpcWidgetState extends State { - SidechainRPC get rpc => GetIt.I.get(); - final TextEditingController _textController = TextEditingController(); - dynamic _result; - String _command = ''; - String? _error; - - Future _callRpc(String args) async { - if (args.trim().isEmpty) { - throw 'Must provide method name'; - } - - final fields = args.trim().split(' ').where((field) => field.isNotEmpty); - - final start = DateTime.now(); - - List params = []; - if (fields.length > 1) { - params = fields.skip(1).toList(); - } - - final method = fields.first; - var res = await rpc.callRAW(method, params); - - log.t( - 'bitcoin core: $method completed in ${DateTime.now().difference(start)}', - error: jsonEncode(res), - ); - - return res; - } - - void _handleSubmit() async { - try { - var res = await _callRpc(_textController.text); - - setState(() { - _command = _textController.text; - _result = res; - _error = null; - }); - } catch (e) { - setState(() { - _result = null; - _error = e.toString(); - }); - } - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - Row( - children: [ - SailText.primary13( - 'RPC:', - ), - Expanded( - child: TextField( - controller: _textController, - ), - ), - ElevatedButton( - onPressed: _handleSubmit, - child: SailText.primary13('Submit'), - ), - ], - ), - if (_result != null) _JsonViewer(_result), - if (_error != null) SailText.primary13('Error: $_command: $_error'), - ], - ), - ); - } -} - -class _JsonViewer extends StatelessWidget { - final dynamic json; - - const _JsonViewer(this.json); - - String prettyPrintJson(dynamic json) { - JsonEncoder encoder = const JsonEncoder.withIndent(' '); - var printed = encoder.convert(json); - return printed; - } - - @override - Widget build(BuildContext context) { - return HighlightView( - prettyPrintJson(json), - language: 'json', - theme: githubTheme, - textStyle: const TextStyle(fontFamily: 'monospace'), - padding: const EdgeInsets.all(12), - ); - } -} diff --git a/lib/pages/tabs/ethereum/ethereum_rpc_tab_page.dart b/lib/pages/tabs/ethereum/ethereum_rpc_tab_page.dart index c4804e75..bd9de730 100644 --- a/lib/pages/tabs/ethereum/ethereum_rpc_tab_page.dart +++ b/lib/pages/tabs/ethereum/ethereum_rpc_tab_page.dart @@ -2,8 +2,8 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:sail_ui/sail_ui.dart'; -import 'package:sidesail/console.dart'; import 'package:sidesail/routing/router.dart'; +import 'package:sidesail/widgets/containers/tabs/console.dart'; @RoutePage() class EthereumRPCTabPage extends StatelessWidget { diff --git a/lib/widgets/containers/tabs/console.dart b/lib/widgets/containers/tabs/console.dart new file mode 100644 index 00000000..37001fb5 --- /dev/null +++ b/lib/widgets/containers/tabs/console.dart @@ -0,0 +1,223 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:sail_ui/sail_ui.dart'; +import 'package:sail_ui/theme/theme.dart'; +import 'package:sail_ui/widgets/core/sail_text.dart'; +import 'package:sidesail/logger.dart'; +import 'package:sidesail/rpc/rpc_ethereum.dart'; + +class RPCWidget extends StatefulWidget { + const RPCWidget({super.key}); + + @override + RPCWidgetState createState() => RPCWidgetState(); +} + +class RPCWidgetState extends State { + EthereumRPC get rpc => GetIt.I.get(); + dynamic _result; + String _command = ''; + String? _error; + + Future _callRpc(String args) async { + if (args.trim().isEmpty) { + throw 'Must provide method name'; + } + + final fields = args.trim().split(' ').where((field) => field.isNotEmpty); + + final start = DateTime.now(); + + List params = []; + if (fields.length > 1) { + params = fields.skip(1).toList(); + } + + final method = fields.first; + var res = await rpc.callRAW(method, params); + + log.t( + 'eth: $method completed in ${DateTime.now().difference(start)}', + error: jsonEncode(res), + ); + + return res; + } + + void _handleSubmit(String selection) async { + try { + var res = await _callRpc(selection); + + setState(() { + _command = selection; + _result = res; + _error = null; + }); + } catch (e) { + setState(() { + _command = selection; + _result = null; + _error = e.toString(); + }); + } + } + + @override + Widget build(BuildContext context) { + final theme = SailTheme.of(context); + + return SailColumn( + spacing: SailStyleValues.padding08, + children: [ + Row( + children: [ + Expanded( + child: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) { + if (textEditingValue.text == '') { + return const Iterable.empty(); + } + return ethRpcMethods.where((String option) { + return option.contains(textEditingValue.text.toLowerCase()); + }); + }, + optionsMaxHeight: 500, + fieldViewBuilder: (context, textEditingController, focusNode, onFieldSubmitted) { + return SailTextField( + controller: textEditingController, + label: 'RPC command', + prefix: '> ', + hintText: 'Enter rpc command here', + focusNode: focusNode, + onSubmitted: _handleSubmit, + suffixWidget: SailTextButton( + label: 'Submit', + onPressed: () { + _handleSubmit(textEditingController.text); + }, + ), + ); + }, + optionsViewBuilder: (context, onSelected, options) { + return Scaffold( + backgroundColor: theme.colors.background, + body: Padding( + padding: const EdgeInsets.only(left: SailStyleValues.padding30), + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: SailColumn( + spacing: SailStyleValues.padding08, + withDivider: true, + children: [ + for (final opt in options) + SailScaleButton( + onPressed: () => onSelected(opt), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: SailStyleValues.padding10, + horizontal: SailStyleValues.padding10, + ), + child: SailText.primary12(opt), + ), + ), + ], + ), + ), + ), + ); + }, + onSelected: (String selection) { + _handleSubmit(selection); + }, + ), + ), + ], + ), + if (_result != null) _JSONView(_result), + if (_error != null) _ErrorView('$_command: $_error'), + ], + ); + } +} + +class _JSONView extends StatelessWidget { + final dynamic json; + + const _JSONView(this.json); + + String prettyPrintJson(dynamic json) { + JsonEncoder encoder = const JsonEncoder.withIndent(' '); + var printed = encoder.convert(json); + return printed; + } + + @override + Widget build(BuildContext context) { + return SailRawCard( + padding: true, + child: SailColumn( + spacing: SailStyleValues.padding50, + mainAxisSize: MainAxisSize.min, + children: [ + SailColumn( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: SailStyleValues.padding08, + withDivider: true, + trailingSpacing: true, + children: [ + const ActionHeaderChip(title: 'Response'), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: SailStyleValues.padding10, + ), + child: SailText.primary12(json.toString()), + ), + ], + ), + ], + ), + ); + } +} + +class _ErrorView extends StatelessWidget { + final String error; + + const _ErrorView(this.error); + + @override + Widget build(BuildContext context) { + return SailRawCard( + padding: true, + child: SailColumn( + spacing: SailStyleValues.padding50, + mainAxisSize: MainAxisSize.min, + children: [ + SailColumn( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + spacing: SailStyleValues.padding08, + withDivider: true, + trailingSpacing: true, + children: [ + const SailErrorShadow( + enabled: true, + small: true, + child: ActionHeaderChip(title: 'Error'), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: SailStyleValues.padding10, + ), + child: SailText.primary12(error), + ), + ], + ), + ], + ), + ); + } +}