mirror of
https://github.com/foss42/apidash.git
synced 2025-09-28 01:23:47 +08:00
Introducing the new text editor 🎉
This commit is contained in:
@ -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<EditRequestBody> createState() => _EditRequestBodyState();
|
||||
ConsumerState<EditRequestBody> createState() => _EditRequestBodyState();
|
||||
}
|
||||
|
||||
class _EditRequestBodyState extends State<EditRequestBody> {
|
||||
class _EditRequestBodyState extends ConsumerState<EditRequestBody> {
|
||||
@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<EditRequestBody> {
|
||||
],
|
||||
),
|
||||
),
|
||||
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<DropdownButtonBodyContentType> {
|
||||
@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<ContentType>(
|
||||
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<TextFieldEditor> createState() => _TextFieldEditorState();
|
||||
}
|
||||
|
||||
class _TextFieldEditorState extends ConsumerState<TextFieldEditor> {
|
||||
@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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
103
lib/widgets/editor.dart
Normal file
103
lib/widgets/editor.dart
Normal file
@ -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<TextFieldEditor> createState() => _TextFieldEditorState();
|
||||
}
|
||||
|
||||
class _TextFieldEditorState extends State<TextFieldEditor> {
|
||||
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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user