mirror of
https://github.com/foss42/apidash.git
synced 2025-06-27 02:51:54 +08:00
Fully functional prototype with final UI design
This commit is contained in:
@ -1 +1,11 @@
|
|||||||
include: package:flutter_lints/flutter.yaml
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
errors:
|
||||||
|
invalid_annotation_target: ignore
|
||||||
|
enable-experiment:
|
||||||
|
- records
|
||||||
|
|
||||||
|
linter:
|
||||||
|
rules:
|
||||||
|
constant_identifier_names: false
|
||||||
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import '../models/models.dart';
|
import '../models/models.dart';
|
||||||
import '../providers/providers.dart';
|
import '../providers/providers.dart';
|
||||||
import '../utils/utils.dart';
|
import '../utils/utils.dart';
|
||||||
|
import 'styles.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
|
||||||
class CollectionPane extends ConsumerStatefulWidget {
|
class CollectionPane extends ConsumerStatefulWidget {
|
||||||
@ -38,7 +39,10 @@ class _CollectionPaneState extends ConsumerState<CollectionPane> {
|
|||||||
.read(activeItemIdStateProvider.notifier)
|
.read(activeItemIdStateProvider.notifier)
|
||||||
.update((state) => newId);
|
.update((state) => newId);
|
||||||
},
|
},
|
||||||
child: const Text('+ New'),
|
child: const Text(
|
||||||
|
'+ New',
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -120,12 +124,9 @@ class RequestItem extends ConsumerStatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RequestItemState extends ConsumerState<RequestItem> {
|
class _RequestItemState extends ConsumerState<RequestItem> {
|
||||||
late Color _color;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_color = Colors.grey.shade50;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -133,11 +134,11 @@ class _RequestItemState extends ConsumerState<RequestItem> {
|
|||||||
final activeRequest = ref.watch(activeItemIdStateProvider);
|
final activeRequest = ref.watch(activeItemIdStateProvider);
|
||||||
bool isActiveId = activeRequest == widget.id;
|
bool isActiveId = activeRequest == widget.id;
|
||||||
return Material(
|
return Material(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: borderRadius10,
|
||||||
elevation: isActiveId ? 2 : 0,
|
elevation: isActiveId ? 2 : 0,
|
||||||
color: isActiveId ? Colors.grey.shade300 : _color,
|
color: isActiveId ? colorGrey300 : colorGrey50,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: borderRadius10,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ref
|
ref
|
||||||
.read(activeItemIdStateProvider.notifier)
|
.read(activeItemIdStateProvider.notifier)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import '../../providers/providers.dart';
|
import '../../providers/providers.dart';
|
||||||
|
import '../styles.dart';
|
||||||
import '../../consts.dart';
|
import '../../consts.dart';
|
||||||
|
|
||||||
class EditRequestBody extends StatefulWidget {
|
class EditRequestBody extends StatefulWidget {
|
||||||
@ -13,23 +14,92 @@ class EditRequestBody extends StatefulWidget {
|
|||||||
class _EditRequestBodyState extends State<EditRequestBody> {
|
class _EditRequestBodyState extends State<EditRequestBody> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Container(
|
||||||
|
decoration: tableContainerDecoration,
|
||||||
|
margin: p5,
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: p10,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: const [
|
||||||
|
Text(
|
||||||
|
"Select Content Type:",
|
||||||
|
//style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
child: DropdownButtonBodyContentType(),
|
|
||||||
height: 30,
|
height: 30,
|
||||||
)
|
child: DropdownButtonBodyContentType(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
const Divider(),
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: p10,
|
||||||
child: TextFieldEditor(),
|
child: TextFieldEditor(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DropdownButtonBodyContentType extends ConsumerStatefulWidget {
|
||||||
|
const DropdownButtonBodyContentType({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<DropdownButtonBodyContentType> createState() =>
|
||||||
|
_DropdownButtonBodyContentTypeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DropdownButtonBodyContentTypeState
|
||||||
|
extends ConsumerState<DropdownButtonBodyContentType> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final activeId = ref.watch(activeItemIdStateProvider);
|
||||||
|
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: colorGrey50,
|
||||||
|
value: requestBodyContentType,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.unfold_more_rounded,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
elevation: 4,
|
||||||
|
style: codeStyle.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary), //Theme.of(context).textTheme.bodyMedium,
|
||||||
|
underline: Container(
|
||||||
|
height: 0,
|
||||||
|
),
|
||||||
|
onChanged: (ContentType? value) {
|
||||||
|
ref
|
||||||
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
|
.update(activeId!, requestBodyContentType: value);
|
||||||
|
},
|
||||||
|
borderRadius: borderRadius10,
|
||||||
|
items: ContentType.values
|
||||||
|
.map<DropdownMenuItem<ContentType>>((ContentType value) {
|
||||||
|
return DropdownMenuItem<ContentType>(
|
||||||
|
value: value,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8),
|
||||||
|
child: Text(
|
||||||
|
value.name,
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,9 +131,10 @@ class _TextFieldEditorState extends ConsumerState<TextFieldEditor> {
|
|||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.update(activeId, requestBody: value);
|
.update(activeId, requestBody: value);
|
||||||
},
|
},
|
||||||
|
style: codeStyle,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Enter body",
|
hintText: "Enter content (body)",
|
||||||
hintStyle: TextStyle(color: Colors.grey.shade500),
|
hintStyle: codeStyle.copyWith(color: colorGrey500),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.multiline,
|
keyboardType: TextInputType.multiline,
|
||||||
@ -72,55 +143,3 @@ class _TextFieldEditorState extends ConsumerState<TextFieldEditor> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DropdownButtonBodyContentType extends ConsumerStatefulWidget {
|
|
||||||
const DropdownButtonBodyContentType({
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
ConsumerState<DropdownButtonBodyContentType> createState() =>
|
|
||||||
_DropdownButtonBodyContentTypeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _DropdownButtonBodyContentTypeState
|
|
||||||
extends ConsumerState<DropdownButtonBodyContentType> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final activeId = ref.watch(activeItemIdStateProvider);
|
|
||||||
final reqestModel = ref
|
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
|
||||||
.getRequestModel(activeId!);
|
|
||||||
return DropdownButton<ContentType>(
|
|
||||||
focusColor: Colors.white,
|
|
||||||
value: reqestModel.requestBodyContentType,
|
|
||||||
icon: const Icon(
|
|
||||||
Icons.unfold_more_rounded,
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
elevation: 4,
|
|
||||||
underline: Container(
|
|
||||||
height: 0,
|
|
||||||
//color: Colors.deepPurpleAccent,
|
|
||||||
),
|
|
||||||
onChanged: (ContentType? value) {
|
|
||||||
ref
|
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
|
||||||
.update(activeId!, requestBodyContentType: value);
|
|
||||||
},
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
items: ContentType.values
|
|
||||||
.map<DropdownMenuItem<ContentType>>((ContentType value) {
|
|
||||||
return DropdownMenuItem<ContentType>(
|
|
||||||
value: value,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 8),
|
|
||||||
child: Text(
|
|
||||||
value.name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:multi_split_view/multi_split_view.dart';
|
import 'package:multi_split_view/multi_split_view.dart';
|
||||||
import 'request_pane.dart';
|
import 'request_pane.dart';
|
||||||
import 'response_pane.dart';
|
import 'response_pane.dart';
|
||||||
@ -30,8 +29,8 @@ class _EditorPaneRequestDetailsCardState
|
|||||||
data: MultiSplitViewThemeData(
|
data: MultiSplitViewThemeData(
|
||||||
dividerThickness: 3,
|
dividerThickness: 3,
|
||||||
dividerPainter: DividerPainters.background(
|
dividerPainter: DividerPainters.background(
|
||||||
color: Colors.grey.shade200,
|
color: colorGrey200,
|
||||||
highlightedColor: Colors.grey.shade400,
|
highlightedColor: colorGrey400,
|
||||||
animationEnabled: false,
|
animationEnabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:tab_container/tab_container.dart';
|
import 'package:tab_container/tab_container.dart';
|
||||||
import '../../providers/providers.dart';
|
import '../../providers/providers.dart';
|
||||||
|
import '../styles.dart';
|
||||||
import 'tables.dart';
|
import 'tables.dart';
|
||||||
import 'body_editor.dart';
|
import 'body_editor.dart';
|
||||||
|
|
||||||
@ -28,28 +29,41 @@ class _EditRequestPaneState extends ConsumerState<EditRequestPane> {
|
|||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.getRequestModel(activeId!)
|
.getRequestModel(activeId!)
|
||||||
.requestTabIndex);
|
.requestTabIndex);
|
||||||
return Padding(
|
return TabContainer(
|
||||||
padding: const EdgeInsets.all(5),
|
|
||||||
child: TabContainer(
|
|
||||||
key: Key(activeId),
|
key: Key(activeId),
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
color: Colors.grey.shade100,
|
color: colorGrey100,
|
||||||
onEnd: () {
|
onEnd: () {
|
||||||
ref
|
ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.update(activeId, requestTabIndex: _controller.index);
|
.update(activeId, requestTabIndex: _controller.index);
|
||||||
},
|
},
|
||||||
|
isStringTabs: false,
|
||||||
tabs: const [
|
tabs: const [
|
||||||
|
Text(
|
||||||
'URL Params',
|
'URL Params',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
'Headers',
|
'Headers',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
'Body',
|
'Body',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
style: textStyleButton,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
children: const [
|
children: const [
|
||||||
EditRequestURLParams(),
|
EditRequestURLParams(),
|
||||||
EditRequestHeaders(),
|
EditRequestHeaders(),
|
||||||
EditRequestBody(),
|
EditRequestBody(),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_json_view/flutter_json_view.dart';
|
||||||
|
import '../../providers/providers.dart';
|
||||||
|
import '../../models/request_model.dart';
|
||||||
|
import '../styles.dart';
|
||||||
|
import "../../utils/utils.dart";
|
||||||
|
import "../../consts.dart";
|
||||||
|
|
||||||
class ResponsePane extends ConsumerStatefulWidget {
|
class ResponsePane extends ConsumerStatefulWidget {
|
||||||
const ResponsePane({super.key});
|
const ResponsePane({super.key});
|
||||||
@ -16,12 +24,28 @@ class _ResponsePaneState extends ConsumerState<ResponsePane> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
final activeId = ref.watch(activeItemIdStateProvider);
|
||||||
padding: const EdgeInsets.all(5),
|
final collection = ref.read(collectionStateNotifierProvider);
|
||||||
child: Column(
|
final idIdx = collection.indexWhere((m) => m.id == activeId);
|
||||||
children: [],
|
final status = ref.watch(collectionStateNotifierProvider
|
||||||
),
|
.select((value) => (value[idIdx].responseStatus,
|
||||||
);
|
value[idIdx].message,
|
||||||
|
value[idIdx].responseModel)));
|
||||||
|
if (status.$0 == null) {
|
||||||
|
return const NotSentWidget();
|
||||||
|
}
|
||||||
|
if (status.$0 == -1) {
|
||||||
|
return ErrorMessage(message: status.$1);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
//var responseModel = ref
|
||||||
|
// .read(collectionStateNotifierProvider.notifier)
|
||||||
|
// .getRequestModel(activeId!)
|
||||||
|
// .responseModel;
|
||||||
|
return ResponseViewer(statusCode: status.$0!,
|
||||||
|
message: status.$1,
|
||||||
|
responseModel: status.$2!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -29,3 +53,237 @@ class _ResponsePaneState extends ConsumerState<ResponsePane> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NotSentWidget extends StatelessWidget {
|
||||||
|
const NotSentWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.north_east_rounded,
|
||||||
|
size: 40,
|
||||||
|
color: colorErrorMsg,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Not Sent',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium
|
||||||
|
?.copyWith(color: colorErrorMsg),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ErrorMessage extends StatelessWidget {
|
||||||
|
const ErrorMessage({super.key, required this.message});
|
||||||
|
|
||||||
|
final String? message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.warning_rounded,
|
||||||
|
size: 40,
|
||||||
|
color: colorErrorMsg,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
message ?? 'And error occurred.',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium
|
||||||
|
?.copyWith(color: colorErrorMsg),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final jsonViewTheme = JsonViewTheme(defaultTextStyle : codeStyle,
|
||||||
|
viewType: JsonViewType.collapsible,
|
||||||
|
backgroundColor: colorBg,
|
||||||
|
stringStyle: const TextStyle(color: Colors.brown),
|
||||||
|
closeIcon: const Icon(
|
||||||
|
Icons.arrow_drop_up,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
openIcon : const Icon(
|
||||||
|
Icons.arrow_drop_down,
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
class ResponseViewer extends StatelessWidget {
|
||||||
|
final int statusCode;
|
||||||
|
final String? message;
|
||||||
|
final ResponseModel responseModel;
|
||||||
|
|
||||||
|
const ResponseViewer({
|
||||||
|
super.key,
|
||||||
|
required this.statusCode,
|
||||||
|
required this.message,
|
||||||
|
required this.responseModel,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var requestHeaders = responseModel.requestHeaders ?? {};
|
||||||
|
var responseHeaders = responseModel.headers ?? {};
|
||||||
|
var body = responseModel.body ?? '';
|
||||||
|
return Padding(
|
||||||
|
padding: p10,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: const [
|
||||||
|
Text(
|
||||||
|
"Response",
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width:50,
|
||||||
|
child: Text(
|
||||||
|
statusCode.toString(),
|
||||||
|
style: codeStyle.copyWith(
|
||||||
|
color: getResponseStatusCodeColor(statusCode),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
message ?? "",
|
||||||
|
style: codeStyle.copyWith(
|
||||||
|
color: getResponseStatusCodeColor(statusCode),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width:100,
|
||||||
|
child: Text(
|
||||||
|
humanizeDuration(responseModel.time),
|
||||||
|
style: codeStyle.copyWith(
|
||||||
|
color: getResponseStatusCodeColor(statusCode),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Request Headers (${requestHeaders.length} items)",
|
||||||
|
style: codeStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(requestHeaders.isNotEmpty) TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await Clipboard.setData(ClipboardData(text: json.encode(requestHeaders)));
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Icon(
|
||||||
|
Icons.content_copy,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
Text("Copy")
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if(requestHeaders.isNotEmpty) const SizedBox(height: 5),
|
||||||
|
if(requestHeaders.isNotEmpty) JsonView.map(
|
||||||
|
requestHeaders,
|
||||||
|
theme: jsonViewTheme,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Response Headers (${responseHeaders.length} items)",
|
||||||
|
style: codeStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(responseHeaders.isNotEmpty) TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await Clipboard.setData(ClipboardData(text: json.encode(responseHeaders)));
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Icon(
|
||||||
|
Icons.content_copy,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
Text("Copy")
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if(responseHeaders.isNotEmpty) const SizedBox(height: 5),
|
||||||
|
if(responseHeaders.isNotEmpty) JsonView.map(
|
||||||
|
responseHeaders,
|
||||||
|
theme: jsonViewTheme,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Body ${body.isEmpty ? '(empty)' : ''}",
|
||||||
|
style: codeStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(body.isNotEmpty) TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await Clipboard.setData(ClipboardData(text: body));
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Icon(
|
||||||
|
Icons.content_copy,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
Text("Copy")
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
if(body.isNotEmpty && responseModel.contentType!.startsWith(JSON_MIMETYPE))
|
||||||
|
JsonView.string(
|
||||||
|
body,
|
||||||
|
theme: jsonViewTheme,
|
||||||
|
),
|
||||||
|
if(body.isNotEmpty && responseModel.contentType!.startsWith("text/"))
|
||||||
|
Text(body),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||||||
import 'package:davi/davi.dart';
|
import 'package:davi/davi.dart';
|
||||||
import '../../models/models.dart';
|
import '../../models/models.dart';
|
||||||
import '../../providers/providers.dart';
|
import '../../providers/providers.dart';
|
||||||
|
import '../styles.dart';
|
||||||
|
|
||||||
class EditRequestURLParams extends ConsumerStatefulWidget {
|
class EditRequestURLParams extends ConsumerStatefulWidget {
|
||||||
const EditRequestURLParams({Key? key}) : super(key: key);
|
const EditRequestURLParams({Key? key}) : super(key: key);
|
||||||
@ -26,7 +27,11 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
return TextFormField(
|
return TextFormField(
|
||||||
key: Key("$activeId-$idx-params-k"),
|
key: Key("$activeId-$idx-params-k"),
|
||||||
initialValue: rows[idx].k,
|
initialValue: rows[idx].k,
|
||||||
decoration: const InputDecoration(hintText: "Add URL Parameter"),
|
style: codeStyle,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: codeStyle,
|
||||||
|
hintText: "Add URL Parameter",
|
||||||
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(k: value);
|
rows[idx] = rows[idx].copyWith(k: value);
|
||||||
_onFieldChange(activeId!);
|
_onFieldChange(activeId!);
|
||||||
@ -39,7 +44,11 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
return TextFormField(
|
return TextFormField(
|
||||||
key: Key("$activeId-$idx-params-v"),
|
key: Key("$activeId-$idx-params-v"),
|
||||||
initialValue: rows[idx].v,
|
initialValue: rows[idx].v,
|
||||||
decoration: const InputDecoration(hintText: "Add Value"),
|
style: codeStyle,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: codeStyle,
|
||||||
|
hintText: "Add Value",
|
||||||
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(v: value);
|
rows[idx] = rows[idx].copyWith(v: value);
|
||||||
_onFieldChange(activeId!);
|
_onFieldChange(activeId!);
|
||||||
@ -75,10 +84,13 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
return Column(
|
return Container(
|
||||||
|
decoration: tableContainerDecoration,
|
||||||
|
margin: p5,
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: p10,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -86,33 +98,22 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
|||||||
rows.add(const KVRow("", ""));
|
rows.add(const KVRow("", ""));
|
||||||
model.addRow(const KVRow("", ""));
|
model.addRow(const KVRow("", ""));
|
||||||
},
|
},
|
||||||
child: const Text("+ Add Param"),
|
child: const Text(
|
||||||
|
"+ Add Param",
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: DaviTheme(
|
child: DaviTheme(
|
||||||
data: DaviThemeData(
|
data: tableThemeData,
|
||||||
columnDividerThickness: 1,
|
|
||||||
columnDividerColor: Colors.grey.shade100,
|
|
||||||
row: RowThemeData(dividerColor: Colors.grey.shade100),
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
border: Border(),
|
|
||||||
),
|
|
||||||
header: HeaderThemeData(
|
|
||||||
color: Colors.grey.shade100,
|
|
||||||
columnDividerColor: Colors.grey.shade100,
|
|
||||||
bottomBorderHeight: 1,
|
|
||||||
),
|
|
||||||
headerCell: const HeaderCellThemeData(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Davi<KVRow>(model),
|
child: Davi<KVRow>(model),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,7 +139,11 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
return TextFormField(
|
return TextFormField(
|
||||||
key: Key("$activeId-$idx-headers-k"),
|
key: Key("$activeId-$idx-headers-k"),
|
||||||
initialValue: rows[idx].k,
|
initialValue: rows[idx].k,
|
||||||
decoration: const InputDecoration(hintText: "Add Header Name"),
|
style: codeStyle,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: codeStyle,
|
||||||
|
hintText: "Add Header Name",
|
||||||
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(k: value);
|
rows[idx] = rows[idx].copyWith(k: value);
|
||||||
_onFieldChange(activeId!);
|
_onFieldChange(activeId!);
|
||||||
@ -151,7 +156,11 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
return TextFormField(
|
return TextFormField(
|
||||||
key: Key("$activeId-$idx-headers-v"),
|
key: Key("$activeId-$idx-headers-v"),
|
||||||
initialValue: rows[idx].v,
|
initialValue: rows[idx].v,
|
||||||
decoration: const InputDecoration(hintText: "Add Header Value"),
|
style: codeStyle,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintStyle: codeStyle,
|
||||||
|
hintText: "Add Header Value",
|
||||||
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
rows[idx] = rows[idx].copyWith(v: value);
|
rows[idx] = rows[idx].copyWith(v: value);
|
||||||
_onFieldChange(activeId!);
|
_onFieldChange(activeId!);
|
||||||
@ -187,10 +196,13 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
return Column(
|
return Container(
|
||||||
|
decoration: tableContainerDecoration,
|
||||||
|
margin: p5,
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: p10,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -198,33 +210,22 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
|||||||
rows.add(const KVRow("", ""));
|
rows.add(const KVRow("", ""));
|
||||||
model.addRow(const KVRow("", ""));
|
model.addRow(const KVRow("", ""));
|
||||||
},
|
},
|
||||||
child: const Text("+ Add Header"),
|
child: const Text(
|
||||||
|
"+ Add Header",
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: DaviTheme(
|
child: DaviTheme(
|
||||||
data: DaviThemeData(
|
data: tableThemeData,
|
||||||
columnDividerThickness: 1,
|
|
||||||
columnDividerColor: Colors.grey.shade100,
|
|
||||||
row: RowThemeData(dividerColor: Colors.grey.shade100),
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
border: Border(),
|
|
||||||
),
|
|
||||||
header: HeaderThemeData(
|
|
||||||
color: Colors.grey.shade100,
|
|
||||||
columnDividerColor: Colors.grey.shade100,
|
|
||||||
bottomBorderHeight: 1,
|
|
||||||
),
|
|
||||||
headerCell: const HeaderCellThemeData(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Davi<KVRow>(model),
|
child: Davi<KVRow>(model),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,23 +26,23 @@ class _EditorPaneRequestURLCardState
|
|||||||
return Card(
|
return Card(
|
||||||
shape: cardShape,
|
shape: cardShape,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: 5,
|
vertical: 5,
|
||||||
horizontal: 20,
|
horizontal: 20,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
DropdownButtonHTTPMethod(),
|
const DropdownButtonHTTPMethod(),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
),
|
),
|
||||||
Expanded(
|
const Expanded(
|
||||||
child: URLTextField(),
|
child: URLTextField(),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
),
|
),
|
||||||
Container(
|
SizedBox(
|
||||||
height: 36,
|
height: 36,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@ -51,8 +51,11 @@ class _EditorPaneRequestURLCardState
|
|||||||
.sendRequest(activeId!);
|
.sendRequest(activeId!);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: const [
|
||||||
Text("Send"),
|
Text(
|
||||||
|
"Send",
|
||||||
|
style: textStyleButton,
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
@ -80,14 +83,9 @@ class DropdownButtonHTTPMethod extends ConsumerStatefulWidget {
|
|||||||
|
|
||||||
class _DropdownButtonHTTPMethodState
|
class _DropdownButtonHTTPMethodState
|
||||||
extends ConsumerState<DropdownButtonHTTPMethod> {
|
extends ConsumerState<DropdownButtonHTTPMethod> {
|
||||||
//late HTTPVerb dropdownValue;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
//dropdownValue = ref
|
|
||||||
// .read(collectionStateNotifierProvider.notifier)
|
|
||||||
// .idxOfId(String id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -97,34 +95,31 @@ class _DropdownButtonHTTPMethodState
|
|||||||
final idIdx = collection.indexWhere((m) => m.id == activeId);
|
final idIdx = collection.indexWhere((m) => m.id == activeId);
|
||||||
final method = ref.watch(
|
final method = ref.watch(
|
||||||
collectionStateNotifierProvider.select((value) => value[idIdx].method));
|
collectionStateNotifierProvider.select((value) => value[idIdx].method));
|
||||||
//final model = ref
|
|
||||||
// .read(collectionStateNotifierProvider.notifier)
|
|
||||||
// .getRequestModel(activeId!);
|
|
||||||
return DropdownButton<HTTPVerb>(
|
return DropdownButton<HTTPVerb>(
|
||||||
focusColor: Colors.white,
|
focusColor: colorBg,
|
||||||
//value: collection[idIdx].method,
|
value: method,
|
||||||
value: method, //model.method,
|
|
||||||
icon: const Icon(Icons.unfold_more_rounded),
|
icon: const Icon(Icons.unfold_more_rounded),
|
||||||
elevation: 4,
|
elevation: 4,
|
||||||
underline: Container(
|
underline: Container(
|
||||||
height: 0,
|
height: 0,
|
||||||
//color: Colors.deepPurpleAccent,
|
|
||||||
),
|
),
|
||||||
onChanged: (HTTPVerb? value) {
|
onChanged: (HTTPVerb? value) {
|
||||||
ref
|
ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.update(activeId!, method: value);
|
.update(activeId!, method: value);
|
||||||
},
|
},
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: borderRadius10,
|
||||||
items: HTTPVerb.values.map<DropdownMenuItem<HTTPVerb>>((HTTPVerb value) {
|
items: HTTPVerb.values.map<DropdownMenuItem<HTTPVerb>>((HTTPVerb value) {
|
||||||
return DropdownMenuItem<HTTPVerb>(
|
return DropdownMenuItem<HTTPVerb>(
|
||||||
//alignment: AlignmentDirectional.center,
|
|
||||||
value: value,
|
value: value,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 16),
|
padding: const EdgeInsets.only(left: 16),
|
||||||
child: Text(
|
child: Text(
|
||||||
value.name.toUpperCase(),
|
value.name.toUpperCase(),
|
||||||
style: TextStyle(color: getHTTPMethodColor(value)),
|
style: codeStyle.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: getHTTPMethodColor(value),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -157,9 +152,10 @@ class _URLTextFieldState extends ConsumerState<URLTextField> {
|
|||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.getRequestModel(activeId!)
|
.getRequestModel(activeId!)
|
||||||
.url,
|
.url,
|
||||||
|
style: codeStyle,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Enter API endpoint like api.foss42.com/country/codes",
|
hintText: "Enter API endpoint like api.foss42.com/country/codes",
|
||||||
hintStyle: TextStyle(color: Colors.grey.shade500),
|
hintStyle: codeStyle.copyWith(color: colorGrey500),
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
),
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
|
@ -1,11 +1,51 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:davi/davi.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
|
||||||
|
final codeStyle = GoogleFonts.sourceCodePro();
|
||||||
|
|
||||||
|
const textStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
||||||
|
|
||||||
|
const colorBg = Colors.white;
|
||||||
|
final colorGrey50 = Colors.grey.shade50;
|
||||||
|
final colorGrey100 = Colors.grey.shade100;
|
||||||
|
final colorGrey200 = Colors.grey.shade200;
|
||||||
|
final colorGrey300 = Colors.grey.shade300;
|
||||||
|
final colorGrey400 = Colors.grey.shade400;
|
||||||
|
final colorGrey500 = Colors.grey.shade500;
|
||||||
|
final colorErrorMsg = colorGrey500;
|
||||||
|
|
||||||
|
final borderRadius10 = BorderRadius.circular(10);
|
||||||
final cardShape = RoundedRectangleBorder(
|
final cardShape = RoundedRectangleBorder(
|
||||||
side: const BorderSide(
|
side: const BorderSide(
|
||||||
color: Colors.white70,
|
color: Colors.white70,
|
||||||
width: 1,
|
width: 1,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: borderRadius10,
|
||||||
);
|
);
|
||||||
|
|
||||||
final colorErrorMsg = Colors.grey.shade500;
|
final tableContainerDecoration = BoxDecoration(
|
||||||
|
color: colorBg,
|
||||||
|
borderRadius: borderRadius10,
|
||||||
|
);
|
||||||
|
final tableThemeData = DaviThemeData(
|
||||||
|
columnDividerThickness: 1,
|
||||||
|
columnDividerColor: colorGrey100,
|
||||||
|
row: RowThemeData(dividerColor: colorGrey100),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
border: Border(),
|
||||||
|
),
|
||||||
|
header: HeaderThemeData(
|
||||||
|
color: colorGrey50,
|
||||||
|
columnDividerColor: colorGrey100,
|
||||||
|
bottomBorderHeight: 1,
|
||||||
|
bottomBorderColor: colorGrey100,
|
||||||
|
),
|
||||||
|
headerCell: const HeaderCellThemeData(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
textStyle: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const p5 = EdgeInsets.all(5);
|
||||||
|
const p10 = EdgeInsets.all(10);
|
||||||
|
@ -4,3 +4,73 @@ enum ContentType { json, text }
|
|||||||
|
|
||||||
const DEFAULT_METHOD = HTTPVerb.get;
|
const DEFAULT_METHOD = HTTPVerb.get;
|
||||||
const DEFAULT_BODY_CONTENT_TYPE = ContentType.json;
|
const DEFAULT_BODY_CONTENT_TYPE = ContentType.json;
|
||||||
|
const JSON_MIMETYPE = 'application/json';
|
||||||
|
|
||||||
|
const RESPONSE_CODE_REASONS = {
|
||||||
|
// 100s
|
||||||
|
100: 'Continue',
|
||||||
|
101: 'Switching Protocols',
|
||||||
|
// 200s
|
||||||
|
200: 'OK',
|
||||||
|
201: 'Created',
|
||||||
|
202: 'Accepted',
|
||||||
|
203: 'Non-Authoritative Information',
|
||||||
|
204: 'No Content',
|
||||||
|
205: 'Reset Content',
|
||||||
|
206: 'Partial Content',
|
||||||
|
207: 'Multi-Status',
|
||||||
|
208: 'Already Reported',
|
||||||
|
226: 'IM Used',
|
||||||
|
// 300s
|
||||||
|
300: 'Multiple Choices',
|
||||||
|
301: 'Moved Permanently',
|
||||||
|
302: 'Found',
|
||||||
|
303: 'See Other',
|
||||||
|
304: 'Not Modified',
|
||||||
|
305: 'Use Proxy',
|
||||||
|
306: 'Switch Proxy',
|
||||||
|
307: 'Temporary Redirect',
|
||||||
|
308: 'Permanent Redirect',
|
||||||
|
// 400s
|
||||||
|
400: 'Bad Request',
|
||||||
|
401: 'Unauthorized',
|
||||||
|
402: 'Payment Required',
|
||||||
|
403: 'Forbidden',
|
||||||
|
404: 'Not Found',
|
||||||
|
405: 'Method Not Allowed',
|
||||||
|
406: 'Not Acceptable',
|
||||||
|
407: 'Proxy Authentication Required',
|
||||||
|
408: 'Request Timeout',
|
||||||
|
409: 'Conflict',
|
||||||
|
410: 'Gone',
|
||||||
|
411: 'Length Required',
|
||||||
|
412: 'Precondition Failed',
|
||||||
|
413: 'Payload Too Large',
|
||||||
|
414: 'URI Too Long',
|
||||||
|
415: 'Unsupported Media Type',
|
||||||
|
416: 'Range Not Satisfiable',
|
||||||
|
417: 'Expectation Failed',
|
||||||
|
418: "I'm a Teapot",
|
||||||
|
421: 'Misdirected Request',
|
||||||
|
422: 'Unprocessable Entity',
|
||||||
|
423: 'Locked',
|
||||||
|
424: 'Failed Dependency',
|
||||||
|
425: 'Too Early',
|
||||||
|
426: 'Upgrade Required',
|
||||||
|
428: 'Precondition Required',
|
||||||
|
429: 'Too Many Requests',
|
||||||
|
431: 'Request Header Fields Too Large',
|
||||||
|
451: 'Unavailable For Legal Reasons',
|
||||||
|
// 500s
|
||||||
|
500: 'Internal Server Error',
|
||||||
|
501: 'Not Implemented',
|
||||||
|
502: 'Bad Gateway',
|
||||||
|
503: 'Service Unavailable',
|
||||||
|
504: 'Gateway Timeout',
|
||||||
|
505: 'HTTP Version Not Supported',
|
||||||
|
506: 'Variant Also Negotiates',
|
||||||
|
507: 'Insufficient Storage',
|
||||||
|
508: 'Loop Detected',
|
||||||
|
510: 'Not Extended',
|
||||||
|
511: 'Network Authentication Required',
|
||||||
|
};
|
||||||
|
@ -2,13 +2,14 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:desktop_window/desktop_window.dart';
|
import 'package:desktop_window/desktop_window.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'screens/screens.dart';
|
import 'screens/screens.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
if (!kIsWeb) {
|
if (!kIsWeb) {
|
||||||
await DesktopWindow.setWindowSize(Size(1400, 800));
|
await DesktopWindow.setWindowSize(const Size(1400, 800));
|
||||||
await DesktopWindow.setMinWindowSize(Size(1200, 800));
|
await DesktopWindow.setMinWindowSize(const Size(1200, 800));
|
||||||
}
|
}
|
||||||
runApp(
|
runApp(
|
||||||
const ProviderScope(
|
const ProviderScope(
|
||||||
@ -25,7 +26,8 @@ class App extends StatelessWidget {
|
|||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primarySwatch: Colors.blue,
|
fontFamily: GoogleFonts.openSans().fontFamily,
|
||||||
|
primarySwatch: Colors.indigo,
|
||||||
),
|
),
|
||||||
home: const HomePage(),
|
home: const HomePage(),
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:multi_split_view/multi_split_view.dart';
|
import 'package:multi_split_view/multi_split_view.dart';
|
||||||
import '../components/components.dart';
|
import '../components/components.dart';
|
||||||
|
import '../components/styles.dart';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
const HomePage({Key? key}) : super(key: key);
|
const HomePage({Key? key}) : super(key: key);
|
||||||
@ -32,8 +33,8 @@ class HomePageState extends State<HomePage> {
|
|||||||
data: MultiSplitViewThemeData(
|
data: MultiSplitViewThemeData(
|
||||||
dividerThickness: 4,
|
dividerThickness: 4,
|
||||||
dividerPainter: DividerPainters.background(
|
dividerPainter: DividerPainters.background(
|
||||||
color: Colors.grey.shade200,
|
color: colorGrey200,
|
||||||
highlightedColor: Colors.grey.shade400,
|
highlightedColor: colorGrey400,
|
||||||
animationEnabled: false,
|
animationEnabled: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter_api_tool/consts.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:collection/collection.dart' show mergeMaps;
|
import 'package:collection/collection.dart' show mergeMaps;
|
||||||
import '../models/models.dart';
|
import '../models/models.dart';
|
||||||
|
import '../../consts.dart';
|
||||||
|
|
||||||
const SUPPORTED_URI_SCHEMES = [
|
const SUPPORTED_URI_SCHEMES = [
|
||||||
"https",
|
"https",
|
||||||
|
@ -1,6 +1,25 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
|
||||||
|
Color? getResponseStatusCodeColor(int? statusCode) {
|
||||||
|
if (statusCode == null) {
|
||||||
|
return Colors.grey.shade700;
|
||||||
|
}
|
||||||
|
if (statusCode >= 500) {
|
||||||
|
return Colors.amber.shade900;
|
||||||
|
}
|
||||||
|
if (statusCode >= 400) {
|
||||||
|
return Colors.red.shade800;
|
||||||
|
}
|
||||||
|
if (statusCode >= 300) {
|
||||||
|
return Colors.blue.shade800;
|
||||||
|
}
|
||||||
|
if (statusCode >= 200) {
|
||||||
|
return Colors.green.shade800;
|
||||||
|
}
|
||||||
|
return Colors.grey.shade700;
|
||||||
|
}
|
||||||
|
|
||||||
Color getHTTPMethodColor(HTTPVerb method) {
|
Color getHTTPMethodColor(HTTPVerb method) {
|
||||||
Color col;
|
Color col;
|
||||||
switch (method) {
|
switch (method) {
|
||||||
@ -39,3 +58,22 @@ String getRequestTitleFromUrl(String? url) {
|
|||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String humanizeDuration(Duration? duration) {
|
||||||
|
if (duration == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (duration.inMinutes >= 1) {
|
||||||
|
var min = duration.inMinutes;
|
||||||
|
var secs = duration.inSeconds.remainder(60);
|
||||||
|
return "$min.$secs m";
|
||||||
|
}
|
||||||
|
if (duration.inSeconds >= 1) {
|
||||||
|
var secs = duration.inSeconds;
|
||||||
|
var mili = duration.inMilliseconds.remainder(1000) ~/ 10;
|
||||||
|
return "$secs.$mili s";
|
||||||
|
} else {
|
||||||
|
var mili = duration.inMilliseconds.remainder(1000);
|
||||||
|
return "$mili ms";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
138
pubspec.lock
138
pubspec.lock
@ -42,7 +42,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
|
sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
|
||||||
@ -81,11 +81,35 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.4"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_json_view:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_json_view
|
||||||
|
sha256: "4adc84e96c8bbd1ee874c5b8a3f6a404edccab9757a12edcde4c45c382b95214"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -107,6 +131,30 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
google_fonts:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: google_fonts
|
||||||
|
sha256: "927573f2e8a8d65c17931e21918ad0ab0666b1b636537de7c4932bdb487b190f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.3"
|
||||||
|
http:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.13.5"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.2"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -163,6 +211,78 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.2"
|
version: "1.8.2"
|
||||||
|
path_provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.13"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: "7623b7d4be0f0f7d9a8b5ee6879fc13e4522d4c875ab86801dee4af32b54b83e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.23"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: eec003594f19fe2456ea965ae36b3fc967bc5005f508890aafe31fa75e41d972
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
sha256: "525ad5e07622d19447ad740b1ed5070031f7a5437f44355ae915ff56e986429a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.9"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.6"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
sha256: "642ddf65fde5404f83267e8459ddb4556316d3ee6d511ed193357e25caa3632d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
process:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: process
|
||||||
|
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.4"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -264,6 +384,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
|
xdg_directories:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xdg_directories
|
||||||
|
sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.19.2 <3.0.0"
|
dart: ">=2.19.2 <3.0.0"
|
||||||
flutter: ">=3.0.0"
|
flutter: ">=3.0.0"
|
||||||
|
@ -17,6 +17,8 @@ dependencies:
|
|||||||
davi: ^3.2.0
|
davi: ^3.2.0
|
||||||
http: ^0.13.5
|
http: ^0.13.5
|
||||||
collection: ^1.17.0
|
collection: ^1.17.0
|
||||||
|
flutter_json_view: ^1.0.0
|
||||||
|
google_fonts: ^4.0.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user