Files
apidash/packages/json_field_editor/lib/src/json_field.dart
2025-04-12 23:59:15 +05:30

284 lines
9.6 KiB
Dart

import 'package:extended_text_field/extended_text_field.dart';
import 'package:flutter/material.dart';
import 'package:json_field_editor/json_field_editor.dart';
import 'package:json_field_editor/src/error_message_container.dart';
import 'package:json_field_editor/src/json_highlight/json_highlight.dart';
import 'package:json_field_editor/src/json_utils.dart';
class JsonField extends ExtendedTextField {
@override
Type get runtimeType => EditableText;
const JsonField({
super.key,
this.fieldKey,
super.autocorrect,
super.autofillHints,
super.autofocus,
super.buildCounter,
super.canRequestFocus,
super.clipBehavior,
this.controller,
super.cursorColor,
super.cursorHeight,
super.cursorRadius,
super.cursorWidth,
super.decoration,
super.enableInteractiveSelection,
super.enableSuggestions,
super.expands,
super.focusNode,
super.inputFormatters,
super.keyboardAppearance,
super.keyboardType,
super.maxLength,
super.maxLines,
super.minLines,
super.obscureText,
super.onAppPrivateCommand,
super.onChanged,
super.onEditingComplete,
super.onSubmitted,
super.onTap,
super.readOnly,
super.scrollController,
super.scrollPadding,
super.scrollPhysics,
super.showCursor,
super.smartDashesType,
super.smartQuotesType,
super.style,
super.textAlign,
super.textAlignVertical,
super.textCapitalization,
super.textDirection,
super.textInputAction,
super.toolbarOptions,
super.contentInsertionConfiguration,
super.selectionControls,
super.mouseCursor,
super.dragStartBehavior,
super.cursorOpacityAnimates,
super.enableIMEPersonalizedLearning,
super.enabled,
super.extendedContextMenuBuilder,
super.extendedSpellCheckConfiguration,
super.maxLengthEnforcement,
super.obscuringCharacter,
super.onTapOutside,
super.restorationId,
super.scribbleEnabled,
super.selectionHeightStyle,
super.selectionWidthStyle,
super.strutStyle,
super.undoController,
this.keyHighlightStyle,
this.stringHighlightStyle,
this.numberHighlightStyle,
this.boolHighlightStyle,
this.nullHighlightStyle,
this.specialCharHighlightStyle,
this.errorTextStyle,
this.commonTextStyle,
this.errorContainerDecoration,
this.showErrorMessage = false,
this.isFormatting = true,
this.doInitFormatting = false,
this.onError,
});
/// If true, the text will be formatted as json. If false, the text field will behave as a normal text field. Default is true.
final bool isFormatting;
/// If true, the text will be formatted during initialization
final bool doInitFormatting;
/// Provide the key value for ExtendedTextField widget
final String? fieldKey;
/// TextStyle for the json key.
final TextStyle? keyHighlightStyle;
/// TextStyle for the json string.
final TextStyle? stringHighlightStyle;
/// TextStyle for the json number.
final TextStyle? numberHighlightStyle;
/// TextStyle for the json bool.
final TextStyle? boolHighlightStyle;
/// TextStyle for the json null.
final TextStyle? nullHighlightStyle;
/// TextStyle for the json special character.
final TextStyle? specialCharHighlightStyle;
/// TextStyle for the error message.
final TextStyle? errorTextStyle;
/// TextStyle for the common text.
final TextStyle? commonTextStyle;
/// If true, the error message will be shown, at bottom of the text field. Default is false.
final bool showErrorMessage;
/// Decoration for the error message container.
final BoxDecoration? errorContainerDecoration;
/// Callback for the error message.
final Function(String?)? onError;
@override
final JsonTextFieldController? controller;
@override
JsonFieldState createState() {
return JsonFieldState();
}
}
class JsonFieldState extends State<JsonField> {
late final JsonTextFieldController controller =
widget.controller ?? JsonTextFieldController();
late String? jsonError =
controller.text.isEmpty
? null
: JsonUtils.getJsonParsingError(controller.text);
late TextStyle style = widget.style ?? const TextStyle();
late final TextStyle keyHighlightStyle =
widget.keyHighlightStyle ??
style.copyWith(
fontWeight: FontWeight.bold,
color: const Color.fromARGB(255, 68, 143, 255),
);
late final TextStyle stringHighlightStyle =
widget.stringHighlightStyle ?? style.copyWith(color: Colors.green[900]);
late final TextStyle numberHighlightStyle =
widget.numberHighlightStyle ?? style.copyWith(color: Colors.purple[900]);
late final TextStyle boolHighlightStyle =
widget.boolHighlightStyle ??
style.copyWith(color: Colors.purple[900], fontWeight: FontWeight.bold);
late final TextStyle nullHighlightStyle =
widget.nullHighlightStyle ??
style.copyWith(color: Colors.grey[600], fontWeight: FontWeight.bold);
late final TextStyle specialCharHighlightStyle =
widget.specialCharHighlightStyle ??
style.copyWith(color: Colors.grey[700]);
late final TextStyle errorTextStyle =
widget.errorTextStyle ?? style.copyWith(color: Colors.red);
late final TextStyle commonTextStyle =
widget.commonTextStyle ?? style.copyWith(color: Colors.black);
@override
void initState() {
controller.text =
(widget.doInitFormatting &&
widget.isFormatting &&
JsonUtils.isValidJson(controller.text))
? JsonUtils.getPrettyPrintJson(controller.text)
: controller.text;
super.initState();
}
void _setJsonError(String? error) => setState(() => jsonError = error);
@override
Widget build(BuildContext context) {
return Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
ExtendedTextField(
key: widget.fieldKey != null ? ValueKey(widget.fieldKey!) : null,
autocorrect: widget.autocorrect,
autofillHints: widget.autofillHints,
autofocus: widget.autofocus,
buildCounter: widget.buildCounter,
canRequestFocus: widget.canRequestFocus,
clipBehavior: widget.clipBehavior,
controller: controller,
cursorColor: widget.cursorColor,
cursorHeight: widget.cursorHeight,
cursorRadius: widget.cursorRadius,
cursorWidth: widget.cursorWidth,
decoration: widget.decoration,
enableInteractiveSelection: widget.enableInteractiveSelection,
enableSuggestions: widget.enableSuggestions,
expands: widget.expands,
focusNode: widget.focusNode,
inputFormatters: widget.inputFormatters,
keyboardAppearance: widget.keyboardAppearance,
keyboardType: widget.keyboardType,
maxLength: widget.maxLength,
maxLines: widget.maxLines,
minLines: widget.minLines,
obscureText: widget.obscureText,
onAppPrivateCommand: widget.onAppPrivateCommand,
onChanged: (value) {
widget.onChanged?.call(value);
if (widget.isFormatting) {
JsonUtils.validateJson(
json: value,
onError: (error) {
_setJsonError(error);
widget.onError?.call(error);
},
);
}
},
onEditingComplete: widget.onEditingComplete,
onSubmitted: widget.onSubmitted,
onTap: widget.onTap,
readOnly: widget.readOnly,
scrollController: widget.scrollController,
scrollPadding: widget.scrollPadding,
scrollPhysics: widget.scrollPhysics,
showCursor: widget.showCursor,
smartDashesType: widget.smartDashesType,
smartQuotesType: widget.smartQuotesType,
specialTextSpanBuilder: JsonHighlight(
boolHighlightStyle: boolHighlightStyle,
keyHighlightStyle: keyHighlightStyle,
nullHighlightStyle: nullHighlightStyle,
numberHighlightStyle: numberHighlightStyle,
specialCharHighlightStyle: stringHighlightStyle,
stringHighlightStyle: stringHighlightStyle,
commonTextStyle: commonTextStyle,
isFormating: widget.isFormatting,
),
style: widget.style,
textAlign: widget.textAlign,
textAlignVertical: widget.textAlignVertical,
textCapitalization: widget.textCapitalization,
textDirection: widget.textDirection,
textInputAction: widget.textInputAction,
contentInsertionConfiguration: widget.contentInsertionConfiguration,
selectionControls: widget.selectionControls,
mouseCursor: widget.mouseCursor,
dragStartBehavior: widget.dragStartBehavior,
cursorOpacityAnimates: widget.cursorOpacityAnimates,
enableIMEPersonalizedLearning: widget.enableIMEPersonalizedLearning,
enabled: widget.enabled,
maxLengthEnforcement: widget.maxLengthEnforcement,
obscuringCharacter: widget.obscuringCharacter,
onTapOutside: widget.onTapOutside,
restorationId: widget.restorationId,
scribbleEnabled: widget.scribbleEnabled,
selectionHeightStyle: widget.selectionHeightStyle,
selectionWidthStyle: widget.selectionWidthStyle,
strutStyle: widget.strutStyle,
undoController: widget.undoController,
),
if (widget.isFormatting && widget.showErrorMessage)
ErrorMessageContainer(
jsonError: jsonError,
errorTextStyle: errorTextStyle,
decoration:
widget.errorContainerDecoration ??
const BoxDecoration(color: Colors.amber),
),
],
);
}
}