diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart index 529c6626..ec001e25 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_body.dart @@ -1,20 +1,28 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:apidash/providers/providers.dart'; +import 'package:apidash/widgets/editor.dart'; import 'package:apidash/consts.dart'; -class EditRequestBody extends StatefulWidget { +class EditRequestBody extends ConsumerStatefulWidget { const EditRequestBody({super.key}); @override - State createState() => _EditRequestBodyState(); + ConsumerState createState() => _EditRequestBodyState(); } -class _EditRequestBodyState extends State { +class _EditRequestBodyState extends ConsumerState { @override Widget build(BuildContext context) { + final activeId = ref.watch(activeIdStateProvider); + final reqestModel = ref + .read(collectionStateNotifierProvider.notifier) + .getRequestModel(activeId!); return Container( - decoration: kTableContainerDecoration, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + borderRadius: kBorder12, + ), margin: kP5, child: Column( children: [ @@ -31,8 +39,16 @@ class _EditRequestBodyState extends State { ], ), ), - const Expanded( - child: TextFieldEditor(), + Expanded( + child: TextFieldEditor( + fieldKey: "$activeId-body", + initialValue: reqestModel.requestBody, + onChanged: (String value) { + ref + .read(collectionStateNotifierProvider.notifier) + .update(activeId, requestBody: value); + }, + ), ) ], ), @@ -54,13 +70,14 @@ class _DropdownButtonBodyContentTypeState extends ConsumerState { @override Widget build(BuildContext context) { + final surfaceColor = Theme.of(context).colorScheme.surface; final activeId = ref.watch(activeIdStateProvider); final collection = ref.read(collectionStateNotifierProvider); final idIdx = collection.indexWhere((m) => m.id == activeId); final requestBodyContentType = ref.watch(collectionStateNotifierProvider .select((value) => value[idIdx].requestBodyContentType)); return DropdownButton( - focusColor: kColorGrey50, + focusColor: surfaceColor, value: requestBodyContentType, icon: const Icon( Icons.unfold_more_rounded, @@ -95,55 +112,3 @@ class _DropdownButtonBodyContentTypeState ); } } - -class TextFieldEditor extends ConsumerStatefulWidget { - const TextFieldEditor({Key? key}) : super(key: key); - - @override - ConsumerState createState() => _TextFieldEditorState(); -} - -class _TextFieldEditorState extends ConsumerState { - @override - void initState() { - super.initState(); - } - - @override - Widget build(BuildContext context) { - final activeId = ref.watch(activeIdStateProvider); - final reqestModel = ref - .read(collectionStateNotifierProvider.notifier) - .getRequestModel(activeId!); - return TextFormField( - key: Key("$activeId-body"), - keyboardType: TextInputType.multiline, - expands: true, - maxLines: null, - textAlignVertical: TextAlignVertical.top, - initialValue: reqestModel.requestBody ?? "", - style: kCodeStyle, - onChanged: (value) { - ref - .read(collectionStateNotifierProvider.notifier) - .update(activeId, requestBody: value); - }, - decoration: InputDecoration( - hintText: "Enter content (body)", - hintStyle: kCodeHintStyle, - focusedBorder: OutlineInputBorder( - borderRadius: kBorder12, - borderSide: BorderSide( - color: Theme.of(context).colorScheme.surfaceVariant, - ), - ), - enabledBorder: OutlineInputBorder( - borderRadius: kBorder12, - borderSide: BorderSide( - color: Theme.of(context).colorScheme.surfaceVariant, - ), - ), - ), - ); - } -} diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart new file mode 100644 index 00000000..bcbaf876 --- /dev/null +++ b/lib/widgets/editor.dart @@ -0,0 +1,103 @@ +import 'dart:math' as math; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:apidash/consts.dart'; + +class TextFieldEditor extends StatefulWidget { + const TextFieldEditor( + {Key? key, required this.fieldKey, this.onChanged, this.initialValue}) + : super(key: key); + + final String fieldKey; + final Function(String)? onChanged; + final String? initialValue; + @override + State createState() => _TextFieldEditorState(); +} + +class _TextFieldEditorState extends State { + final TextEditingController controller = TextEditingController(); + final editorFocusNode = FocusNode(); + final keyboardListnerFocusNode = FocusNode(); + + @override + void initState() { + super.initState(); + } + + void insertTab() { + String sp = " "; + int offset = math.min( + controller.selection.baseOffset, controller.selection.extentOffset); + String text = controller.text.substring(0, offset) + + sp + + controller.text.substring(offset); + controller.value = TextEditingValue( + text: text, + selection: controller.selection.copyWith( + baseOffset: controller.selection.baseOffset + sp.length, + extentOffset: controller.selection.extentOffset + sp.length, + ), + ); + } + + @override + Widget build(BuildContext context) { + if (widget.initialValue != null) { + controller.text = widget.initialValue!; + } + return RawKeyboardListener( + focusNode: keyboardListnerFocusNode, + onKey: (RawKeyEvent event) { + if (event.runtimeType == RawKeyDownEvent && + (event.logicalKey == LogicalKeyboardKey.tab)) { + if (kIsWeb) { + FocusScope.of(context).previousFocus(); + } else { + editorFocusNode.requestFocus(); + } + insertTab(); + } + }, + child: TextFormField( + key: Key(widget.fieldKey), + controller: controller, + focusNode: editorFocusNode, + keyboardType: TextInputType.multiline, + expands: true, + maxLines: null, + style: kCodeStyle, + textAlignVertical: TextAlignVertical.top, + onChanged: widget.onChanged, + decoration: InputDecoration( + hintText: "Enter content (body)", + hintStyle: TextStyle( + color: Theme.of(context).colorScheme.outline.withOpacity( + kHintOpacity, + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.primary.withOpacity( + kHintOpacity, + ), + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Theme.of(context).colorScheme.surfaceVariant, + ), + ), + ), + ), + ); + } + + @override + void dispose() { + keyboardListnerFocusNode.dispose(); + editorFocusNode.dispose(); + super.dispose(); + } +}