diff --git a/lib/screens/history/history_widgets/his_request_pane.dart b/lib/screens/history/history_widgets/his_request_pane.dart index dc618e77..a64b96f8 100644 --- a/lib/screens/history/history_widgets/his_request_pane.dart +++ b/lib/screens/history/history_widgets/his_request_pane.dart @@ -140,7 +140,7 @@ class HisRequestBody extends ConsumerWidget { // TODO: Fix JsonTextFieldEditor & plug it here ContentType.json => Padding( padding: kPt5o10, - child: TextFieldEditor( + child: JsonTextFieldEditor( key: Key("${selectedHistoryModel?.historyId}-json-body"), fieldKey: "${selectedHistoryModel?.historyId}-json-body-viewer", 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 c679f277..8c5a805d 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 @@ -20,6 +20,9 @@ class EditRequestBody extends ConsumerWidget { .select((value) => value?.httpRequestModel?.bodyContentType)); final apiType = ref .watch(selectedRequestModelProvider.select((value) => value?.apiType)); + final mode = ref.watch(settingsProvider.select( + (value) => value.isDark, + )); return Column( children: [ @@ -42,12 +45,11 @@ class EditRequestBody extends ConsumerWidget { child: switch (contentType) { ContentType.formdata => const Padding(padding: kPh4, child: FormDataWidget()), - // TODO: Fix JsonTextFieldEditor & plug it here ContentType.json => Padding( padding: kPt5o10, - child: TextFieldEditor( + child: JsonTextFieldEditor( key: Key("$selectedId-json-body"), - fieldKey: "$selectedId-json-body-editor", + fieldKey: "$selectedId-json-body-editor-$mode", initialValue: requestModel?.httpRequestModel?.body, onChanged: (String value) { ref diff --git a/lib/widgets/editor_json.dart b/lib/widgets/editor_json.dart index 3c0c2abf..33f026c5 100644 --- a/lib/widgets/editor_json.dart +++ b/lib/widgets/editor_json.dart @@ -1,9 +1,9 @@ import 'dart:math' as math; -import 'package:apidash/consts.dart'; import 'package:apidash_design_system/apidash_design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:json_text_field/json_text_field.dart'; +import 'package:apidash/consts.dart'; class JsonTextFieldEditor extends StatefulWidget { const JsonTextFieldEditor({ @@ -11,11 +11,15 @@ class JsonTextFieldEditor extends StatefulWidget { required this.fieldKey, this.onChanged, this.initialValue, + this.hintText, + this.readOnly = false, }); final String fieldKey; final Function(String)? onChanged; final String? initialValue; + final String? hintText; + final bool readOnly; @override State createState() => _JsonTextFieldEditorState(); } @@ -44,6 +48,9 @@ class _JsonTextFieldEditorState extends State { @override void initState() { super.initState(); + if (widget.initialValue != null) { + controller.text = widget.initialValue!; + } controller.formatJson(sortJson: false); editorFocusNode = FocusNode(debugLabel: "Editor Focus Node"); } @@ -55,75 +62,127 @@ class _JsonTextFieldEditorState extends State { } @override - Widget build(BuildContext context) { - if (widget.initialValue != null) { - controller.text = widget.initialValue!; + void didUpdateWidget(JsonTextFieldEditor oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.initialValue != widget.initialValue) { + controller.text = widget.initialValue ?? ""; + controller.selection = + TextSelection.collapsed(offset: controller.text.length); } - return CallbackShortcuts( - bindings: { - const SingleActivator(LogicalKeyboardKey.tab): () { - insertTab(); - }, - }, - child: JsonTextField( - stringHighlightStyle: kCodeStyle.copyWith( - color: Theme.of(context).colorScheme.secondary, - ), - keyHighlightStyle: kCodeStyle.copyWith( - color: Theme.of(context).colorScheme.primary, - fontWeight: FontWeight.bold, - ), - errorContainerDecoration: BoxDecoration( - color: Theme.of(context).colorScheme.error.withOpacity( - kForegroundOpacity, + if (oldWidget.fieldKey != widget.fieldKey) { + // TODO: JsonTextField uses ExtendedTextField which does + // not rebuild because no key is provided + // so light mode to dark mode switching leads to incorrect color. + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + CallbackShortcuts( + bindings: { + const SingleActivator(LogicalKeyboardKey.tab): () { + insertTab(); + }, + }, + child: JsonTextField( + key: Key(widget.fieldKey), + commonTextStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['root']?.color + : kLightCodeTheme['root']?.color, + ), + specialCharHighlightStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['root']?.color + : kLightCodeTheme['root']?.color, + ), + stringHighlightStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['string']?.color + : kLightCodeTheme['string']?.color, + ), + numberHighlightStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['number']?.color + : kLightCodeTheme['number']?.color, + ), + boolHighlightStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['literal']?.color + : kLightCodeTheme['literal']?.color, + ), + nullHighlightStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['variable']?.color + : kLightCodeTheme['variable']?.color, + ), + keyHighlightStyle: kCodeStyle.copyWith( + color: Theme.of(context).brightness == Brightness.dark + ? kDarkCodeTheme['attr']?.color + : kLightCodeTheme['attr']?.color, + fontWeight: FontWeight.bold, + ), + // errorContainerDecoration: BoxDecoration( + // color: Theme.of(context).colorScheme.error.withOpacity( + // kForegroundOpacity, + // ), + // borderRadius: kBorderRadius8, + // ), + // TODO: Show error message in Global Status bar + // showErrorMessage: true, + isFormatting: true, + controller: controller, + focusNode: editorFocusNode, + keyboardType: TextInputType.multiline, + expands: true, + maxLines: null, + readOnly: widget.readOnly, + style: kCodeStyle.copyWith( + fontSize: Theme.of(context).textTheme.bodyMedium?.fontSize, + ), + textAlignVertical: TextAlignVertical.top, + onChanged: widget.onChanged, + onTapOutside: (PointerDownEvent event) { + editorFocusNode.unfocus(); + }, + decoration: InputDecoration( + hintText: widget.hintText ?? kHintContent, + hintStyle: TextStyle( + color: Theme.of(context).colorScheme.outlineVariant, ), - borderRadius: kBorderRadius8, - ), - showErrorMessage: true, - isFormatting: true, - key: Key(widget.fieldKey), - controller: controller, - focusNode: editorFocusNode, - keyboardType: TextInputType.multiline, - expands: true, - maxLines: null, - style: kCodeStyle, - textAlignVertical: TextAlignVertical.top, - onChanged: (value) { - controller.formatJson(sortJson: false); - widget.onChanged?.call(value); - }, - decoration: InputDecoration( - hintText: kHintJson, - hintStyle: TextStyle( - color: Theme.of(context).colorScheme.outline.withOpacity( - kHintOpacity, + focusedBorder: OutlineInputBorder( + borderRadius: kBorderRadius8, + borderSide: BorderSide( + color: Theme.of(context).colorScheme.outlineVariant, ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: kBorderRadius8, - borderSide: BorderSide( - color: Theme.of(context).colorScheme.primary.withOpacity( - kHintOpacity, - ), + ), + enabledBorder: OutlineInputBorder( + borderRadius: kBorderRadius8, + borderSide: BorderSide( + color: Theme.of(context).colorScheme.surfaceContainerHighest, + ), + ), + filled: true, + hoverColor: kColorTransparent, + fillColor: Theme.of(context).colorScheme.surfaceContainerLow, ), ), - enabledBorder: OutlineInputBorder( - borderRadius: kBorderRadius8, - borderSide: BorderSide( - color: Theme.of(context).colorScheme.surfaceContainerHighest, - ), - ), - filled: true, - hoverColor: kColorTransparent, - fillColor: 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), ), - ), + Align( + alignment: Alignment.topRight, + child: ADIconButton( + icon: Icons.format_align_left, + tooltip: "Format JSON", + onPressed: () { + controller.formatJson(sortJson: false); + widget.onChanged?.call(controller.text); + }, + ), + ), + ], ); } } diff --git a/lib/widgets/request_pane.dart b/lib/widgets/request_pane.dart index 95871d53..09ebd0a3 100644 --- a/lib/widgets/request_pane.dart +++ b/lib/widgets/request_pane.dart @@ -63,13 +63,16 @@ class _RequestPaneState extends State widget.codePaneVisible ? Icons.code_off_rounded : Icons.code_rounded, + size: 18, ), label: SizedBox( - width: 75, + width: 80, child: Text( widget.codePaneVisible ? kLabelHideCode : kLabelViewCode, + overflow: TextOverflow.ellipsis, + maxLines: 1, ), ), ),