mirror of
https://github.com/foss42/apidash.git
synced 2025-05-22 08:46:33 +08:00
Merge branch 'main' into refactor
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -50,6 +50,7 @@ macos/
|
||||
windows/
|
||||
web/
|
||||
ios/
|
||||
android/
|
||||
.vscode/*
|
||||
icons/
|
||||
coverage/*
|
||||
|
@ -3,7 +3,11 @@
|
||||
## Windows
|
||||
Download the latest Windows Installer (64 bit) from [here](https://github.com/foss42/apidash/releases/latest)
|
||||
|
||||
To install it, simply double click on the installer and follow the step by step installation wizard.
|
||||
To install it, simply double click on the installer.
|
||||
|
||||
If prompted by Windows that **Windows prevented an unrecognized app from running**, click on **Run anyway**.
|
||||
|
||||
Now, follow the step by step installation wizard.
|
||||
|
||||
## MacOS
|
||||
|
||||
|
22
README.md
22
README.md
@ -27,35 +27,41 @@ API Dash can be downloaded from the links below:
|
||||
<td><code>.dmg</code></td>
|
||||
<td><a href="https://github.com/foss42/apidash/blob/main/INSTALLATION.md#macos">Link</a></td>
|
||||
<td>Apple Silicon & Intel</td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/download/latest/apidash-macos.dmg">Link</a></td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/latest/download/apidash-macos.dmg">Link</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Windows</td>
|
||||
<td><code>.exe</code></td>
|
||||
<td><a href="https://github.com/foss42/apidash/blob/main/INSTALLATION.md#windows">Link</a></td>
|
||||
<td>64-bit</td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/download/latest/apidash-windows-x86_64.exe">Link</a></td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/latest/download/apidash-windows-x86_64.exe">Link</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=4>Linux</td>
|
||||
<td rowspan=5>Linux</td>
|
||||
<td rowspan=2><code>.deb</code></td>
|
||||
<td rowspan=2><a href="https://github.com/foss42/apidash/blob/main/INSTALLATION.md#debian-based-linux-distributions-debian-ubuntu-linux-mint-etc">Link</a></td>
|
||||
<td>amd64</td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/download/latest/apidash-linux-amd64.deb">Link</a></td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/latest/download/apidash-linux-amd64.deb">Link</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>arm64</td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/download/latest/apidash-linux-arm64.deb">Link</a></td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/latest/download/apidash-linux-arm64.deb">Link</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=2><code>.rpm</code></td>
|
||||
<td rowspan=2><a href="https://github.com/foss42/apidash/blob/main/INSTALLATION.md#red-hat-based-linux-distributions-fedora-rocky-almalinux-centos-rhel-etc">Link</a></td>
|
||||
<td>x86_64</td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/download/latest/apidash-linux-x86_64.rpm">Link</a></td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/latest/download/apidash-linux-x86_64.rpm">Link</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>aarch64</td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/download/latest/apidash-linux-aarch64.rpm">Link</a></td>
|
||||
<td><a href="https://github.com/foss42/apidash/releases/latest/download/apidash-linux-aarch64.rpm">Link</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>PKGBUILD</code> (Arch Linux)</td>
|
||||
<td><a href="https://aur.archlinux.org/packages/apidash-bin">Link</a></td>
|
||||
<td>x86_64</td>
|
||||
<td><a href="https://aur.archlinux.org/packages/apidash-bin">Link</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -132,7 +138,7 @@ Here is the complete list of mimetypes that can be directly previewed in API Das
|
||||
| Image | `image/portable-anymap` | `.pnm` | |
|
||||
| Image | `image/png` | `.png` | |
|
||||
| Image | `image/sgi` | `.sgi` | |
|
||||
| Image | `image/svg+xml` | `.svg` | Partial support. See issue https://github.com/foss42/apidash/issues/20 |
|
||||
| Image | `image/svg+xml` | `.svg` | |
|
||||
| Image | `image/tiff` | `.tiff` | |
|
||||
| Image | `image/targa` | `.tga` | |
|
||||
| Image | `image/vnd.wap.wbmp` | `.wbmp` | |
|
||||
|
1
devtools_options.yaml
Normal file
1
devtools_options.yaml
Normal file
@ -0,0 +1 @@
|
||||
extensions:
|
28
lib/app.dart
28
lib/app.dart
@ -1,9 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
import 'package:window_manager/window_manager.dart' hide WindowCaption;
|
||||
import 'widgets/widgets.dart' show WindowCaption;
|
||||
import 'providers/providers.dart';
|
||||
import 'screens/screens.dart';
|
||||
import 'consts.dart' show kFontFamily, kFontFamilyFallback, kColorSchemeSeed;
|
||||
import 'consts.dart';
|
||||
|
||||
class App extends ConsumerStatefulWidget {
|
||||
const App({super.key});
|
||||
@ -38,7 +39,7 @@ class _AppState extends ConsumerState<App> with WindowListener {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const DashApp();
|
||||
return const Dashboard();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -63,6 +64,7 @@ class _DashAppState extends ConsumerState<DashApp> {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||
fontFamily: kFontFamily,
|
||||
fontFamilyFallback: kFontFamilyFallback,
|
||||
colorSchemeSeed: kColorSchemeSeed,
|
||||
@ -77,7 +79,25 @@ class _DashAppState extends ConsumerState<DashApp> {
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
themeMode: isDarkMode ? ThemeMode.dark : ThemeMode.light,
|
||||
home: const Dashboard(),
|
||||
home: kIsMobile
|
||||
? const MobileDashboard(
|
||||
title: 'Requests',
|
||||
scaffoldBody: CollectionPane(),
|
||||
)
|
||||
: Stack(
|
||||
children: [
|
||||
kIsLinux ? const Dashboard() : const App(),
|
||||
if (kIsWindows)
|
||||
SizedBox(
|
||||
height: 29,
|
||||
child: WindowCaption(
|
||||
backgroundColor: Colors.transparent,
|
||||
brightness:
|
||||
isDarkMode ? Brightness.dark : Brightness.light,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:apidash/models/models.dart' show RequestModel;
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'dart/http.dart';
|
||||
import 'dart/dio.dart';
|
||||
import 'kotlin/okhttp.dart';
|
||||
import 'python/http_client.dart';
|
||||
import 'python/requests.dart';
|
||||
@ -22,6 +23,8 @@ class Codegen {
|
||||
return HARCodeGen().getCode(requestModel, defaultUriScheme);
|
||||
case CodegenLanguage.dartHttp:
|
||||
return DartHttpCodeGen().getCode(requestModel, defaultUriScheme);
|
||||
case CodegenLanguage.dartDio:
|
||||
return DartDioCodeGen().getCode(requestModel, defaultUriScheme);
|
||||
case CodegenLanguage.jsAxios:
|
||||
return AxiosCodeGen().getCode(requestModel, defaultUriScheme);
|
||||
case CodegenLanguage.jsFetch:
|
||||
@ -39,8 +42,6 @@ class Codegen {
|
||||
.getCode(requestModel, defaultUriScheme);
|
||||
case CodegenLanguage.pythonRequests:
|
||||
return PythonRequestsCodeGen().getCode(requestModel, defaultUriScheme);
|
||||
default:
|
||||
throw ArgumentError('Invalid codegenLanguage');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
148
lib/codegen/dart/dio.dart
Normal file
148
lib/codegen/dart/dio.dart
Normal file
@ -0,0 +1,148 @@
|
||||
import 'dart:convert';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:apidash/models/request_model.dart' show RequestModel;
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'shared.dart';
|
||||
|
||||
class DartDioCodeGen {
|
||||
String? getCode(
|
||||
RequestModel requestModel,
|
||||
String defaultUriScheme,
|
||||
) {
|
||||
try {
|
||||
String url = requestModel.url;
|
||||
if (!url.contains("://") && url.isNotEmpty) {
|
||||
url = "$defaultUriScheme://$url";
|
||||
}
|
||||
final next = generatedDartCode(
|
||||
url: url,
|
||||
method: requestModel.method,
|
||||
queryParams: requestModel.enabledParamsMap,
|
||||
headers: requestModel.enabledHeadersMap,
|
||||
body: requestModel.requestBody,
|
||||
contentType: requestModel.requestBodyContentType,
|
||||
formData: requestModel.formDataMapList,
|
||||
);
|
||||
return next;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String generatedDartCode({
|
||||
required String url,
|
||||
required HTTPVerb method,
|
||||
required Map<String, String> queryParams,
|
||||
required Map<String, String> headers,
|
||||
required String? body,
|
||||
required ContentType contentType,
|
||||
required List<Map<String, dynamic>> formData,
|
||||
}) {
|
||||
final sbf = StringBuffer();
|
||||
final emitter = DartEmitter();
|
||||
final dioImport = Directive.import('package:dio/dio.dart', as: 'dio');
|
||||
sbf.writeln(dioImport.accept(emitter));
|
||||
|
||||
Expression? queryParamExp;
|
||||
if (queryParams.isNotEmpty) {
|
||||
queryParamExp = declareFinal('queryParams').assign(
|
||||
literalMap(queryParams.map((key, value) => MapEntry(key, value))),
|
||||
);
|
||||
}
|
||||
Expression? headerExp;
|
||||
if (headers.isNotEmpty) {
|
||||
headerExp = declareFinal('headers').assign(
|
||||
literalMap(headers.map((key, value) => MapEntry(key, value))),
|
||||
);
|
||||
}
|
||||
final multiPartList = Code('''
|
||||
final List<Map<String,String>> formDataList = ${json.encode(formData)};
|
||||
for (var formField in formDataList) {
|
||||
if (formField['type'] == 'file') {
|
||||
formData.files.add(MapEntry(
|
||||
formField['name'],
|
||||
await MultipartFile.fromFile(formField['value'], filename: formField['value']),
|
||||
));
|
||||
} else {
|
||||
formData.fields.add(MapEntry(formField['name'], formField['value']));
|
||||
}
|
||||
}
|
||||
''');
|
||||
Expression? dataExp;
|
||||
if ((kMethodsWithBody.contains(method) && (body?.isNotEmpty ?? false) ||
|
||||
contentType == ContentType.formdata)) {
|
||||
final strContent = CodeExpression(Code('r\'\'\'$body\'\'\''));
|
||||
switch (contentType) {
|
||||
// dio dosen't need pass `content-type` header when body is json or plain text
|
||||
case ContentType.json:
|
||||
final convertImport = Directive.import('dart:convert', as: 'convert');
|
||||
sbf.writeln(convertImport.accept(emitter));
|
||||
dataExp = declareFinal('data')
|
||||
.assign(refer('convert.json.decode').call([strContent]));
|
||||
case ContentType.text:
|
||||
dataExp = declareFinal('data').assign(strContent);
|
||||
// when add new type of [ContentType], need update [dataExp].
|
||||
case ContentType.formdata:
|
||||
dataExp = declareFinal('data').assign(refer('FormData()'));
|
||||
}
|
||||
}
|
||||
final responseExp = declareFinal('response').assign(InvokeExpression.newOf(
|
||||
refer('dio.Dio'),
|
||||
[literalString(url)],
|
||||
{
|
||||
if (queryParamExp != null) 'queryParameters': refer('queryParams'),
|
||||
if (headerExp != null)
|
||||
'options': refer('Options').newInstance(
|
||||
[],
|
||||
{'headers': refer('headers')},
|
||||
),
|
||||
if (dataExp != null) 'data': refer('data'),
|
||||
},
|
||||
[],
|
||||
method.name,
|
||||
).awaited);
|
||||
|
||||
final mainFunction = Method((m) {
|
||||
final content = declareTryCatch(
|
||||
showStackStrace: true,
|
||||
body: [
|
||||
if (queryParamExp != null) queryParamExp,
|
||||
if (headerExp != null) headerExp,
|
||||
if (dataExp != null) dataExp,
|
||||
if ((contentType == ContentType.formdata && formData.isNotEmpty))
|
||||
multiPartList,
|
||||
responseExp,
|
||||
refer('print').call([refer('response').property('statusCode')]),
|
||||
refer('print').call([refer('response').property('data')]),
|
||||
],
|
||||
onError: {
|
||||
'DioException': [
|
||||
refer('print').call([
|
||||
refer('e').property('response').nullSafeProperty('statusCode'),
|
||||
]),
|
||||
refer('print').call([
|
||||
refer('e').property('response').nullSafeProperty('data'),
|
||||
]),
|
||||
refer('print').call([refer('s')]),
|
||||
],
|
||||
null: [
|
||||
refer('print').call([refer('e')]),
|
||||
refer('print').call([refer('s')]),
|
||||
],
|
||||
},
|
||||
);
|
||||
m
|
||||
..name = 'main'
|
||||
..returns = refer('void')
|
||||
..modifier = MethodModifier.async
|
||||
..body = content;
|
||||
});
|
||||
|
||||
sbf.writeln(mainFunction.accept(emitter));
|
||||
|
||||
return DartFormatter(
|
||||
pageWidth: contentType == ContentType.formdata ? 70 : 160)
|
||||
.format(sbf.toString());
|
||||
}
|
||||
}
|
@ -1,147 +1,223 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:jinja/jinja.dart' as jj;
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/utils/utils.dart' show padMultilineString;
|
||||
import 'dart:io';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
import 'package:dart_style/dart_style.dart';
|
||||
import 'package:apidash/models/models.dart' show RequestModel;
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'shared.dart';
|
||||
|
||||
class DartHttpCodeGen {
|
||||
String kTemplateStart = """import 'package:http/http.dart' as http;
|
||||
|
||||
void main() async {
|
||||
var uri = Uri.parse('{{url}}');
|
||||
|
||||
""";
|
||||
|
||||
String kTemplateParams = """
|
||||
|
||||
var queryParams = {{params}};
|
||||
""";
|
||||
int kParamsPadding = 20;
|
||||
|
||||
String kStringUrlParams = """
|
||||
|
||||
var urlQueryParams = Map<String,String>.from(uri.queryParameters);
|
||||
urlQueryParams.addAll(queryParams);
|
||||
uri = uri.replace(queryParameters: urlQueryParams);
|
||||
""";
|
||||
|
||||
String kStringNoUrlParams = """
|
||||
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
""";
|
||||
|
||||
String kTemplateBody = """
|
||||
|
||||
String body = r'''{{body}}''';
|
||||
|
||||
""";
|
||||
|
||||
String kTemplateHeaders = """
|
||||
|
||||
var headers = {{headers}};
|
||||
|
||||
""";
|
||||
int kHeadersPadding = 16;
|
||||
|
||||
String kTemplateRequest = """
|
||||
|
||||
final response = await http.{{method}}(uri""";
|
||||
|
||||
String kStringRequestHeaders = """,
|
||||
headers: headers""";
|
||||
|
||||
String kStringRequestBody = """,
|
||||
body: body""";
|
||||
String kStringRequestEnd = r""");
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
String? getCode(
|
||||
RequestModel requestModel,
|
||||
String defaultUriScheme,
|
||||
) {
|
||||
try {
|
||||
String result = "";
|
||||
bool hasHeaders = false;
|
||||
bool hasBody = false;
|
||||
|
||||
String url = requestModel.url;
|
||||
if (!url.contains("://") && url.isNotEmpty) {
|
||||
url = "$defaultUriScheme://$url";
|
||||
}
|
||||
var templateStartUrl = jj.Template(kTemplateStart);
|
||||
result += templateStartUrl.render({"url": url});
|
||||
|
||||
var paramsList = requestModel.requestParams;
|
||||
if (paramsList != null) {
|
||||
var params = requestModel.paramsMap;
|
||||
if (params.isNotEmpty) {
|
||||
var templateParams = jj.Template(kTemplateParams);
|
||||
var paramsString = kEncoder.convert(params);
|
||||
paramsString = padMultilineString(paramsString, kParamsPadding);
|
||||
result += templateParams.render({"params": paramsString});
|
||||
Uri uri = Uri.parse(url);
|
||||
if (uri.hasQuery) {
|
||||
result += kStringUrlParams;
|
||||
} else {
|
||||
result += kStringNoUrlParams;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var method = requestModel.method;
|
||||
var requestBody = requestModel.requestBody;
|
||||
if (kMethodsWithBody.contains(method) && requestBody != null) {
|
||||
var contentLength = utf8.encode(requestBody).length;
|
||||
if (contentLength > 0) {
|
||||
hasBody = true;
|
||||
var templateBody = jj.Template(kTemplateBody);
|
||||
result += templateBody.render({"body": requestBody});
|
||||
}
|
||||
}
|
||||
|
||||
var headersList = requestModel.requestHeaders;
|
||||
if (headersList != null || hasBody) {
|
||||
var headers = requestModel.headersMap;
|
||||
if (headers.isNotEmpty || hasBody) {
|
||||
hasHeaders = true;
|
||||
if (hasBody) {
|
||||
headers[HttpHeaders.contentTypeHeader] =
|
||||
kContentTypeMap[requestModel.requestBodyContentType] ?? "";
|
||||
}
|
||||
var headersString = kEncoder.convert(headers);
|
||||
headersString = padMultilineString(headersString, kHeadersPadding);
|
||||
var templateHeaders = jj.Template(kTemplateHeaders);
|
||||
result += templateHeaders.render({"headers": headersString});
|
||||
}
|
||||
}
|
||||
|
||||
var templateRequest = jj.Template(kTemplateRequest);
|
||||
result += templateRequest.render({"method": method.name});
|
||||
|
||||
if (hasHeaders) {
|
||||
result += kStringRequestHeaders;
|
||||
}
|
||||
|
||||
if (hasBody) {
|
||||
result += kStringRequestBody;
|
||||
}
|
||||
|
||||
result += kStringRequestEnd;
|
||||
return result;
|
||||
final next = generatedDartCode(
|
||||
url: url,
|
||||
method: requestModel.method,
|
||||
queryParams: requestModel.enabledParamsMap,
|
||||
headers: {...requestModel.enabledHeadersMap},
|
||||
contentType: requestModel.requestBodyContentType,
|
||||
hasContentTypeHeader: requestModel.hasContentTypeHeader,
|
||||
body: requestModel.requestBody,
|
||||
formData: requestModel.formDataMapList,
|
||||
);
|
||||
return next;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String generatedDartCode({
|
||||
required String url,
|
||||
required HTTPVerb method,
|
||||
required Map<String, String> queryParams,
|
||||
required Map<String, String> headers,
|
||||
required ContentType contentType,
|
||||
required String? body,
|
||||
required bool hasContentTypeHeader,
|
||||
required List<Map<String, dynamic>> formData,
|
||||
}) {
|
||||
final uri = Uri.parse(url);
|
||||
|
||||
final sbf = StringBuffer();
|
||||
final emitter = DartEmitter();
|
||||
final dioImport = Directive.import('package:http/http.dart', as: 'http');
|
||||
sbf.writeln(dioImport.accept(emitter));
|
||||
|
||||
final uriExp =
|
||||
declareVar('uri').assign(refer('Uri.parse').call([literalString(url)]));
|
||||
|
||||
Expression? dataExp;
|
||||
if (kMethodsWithBody.contains(method) && (body?.isNotEmpty ?? false)) {
|
||||
final strContent = CodeExpression(Code('r\'\'\'$body\'\'\''));
|
||||
dataExp = declareVar('body', type: refer('String')).assign(strContent);
|
||||
if (!hasContentTypeHeader) {
|
||||
headers.putIfAbsent(
|
||||
HttpHeaders.contentTypeHeader, () => contentType.header);
|
||||
}
|
||||
}
|
||||
|
||||
Expression? queryParamExp;
|
||||
List<Expression>? uriReassignExps;
|
||||
// var urlQueryParams = Map<String,String>.from(uri.queryParameters);
|
||||
// urlQueryParams.addAll(queryParams);
|
||||
// uri = uri.replace(queryParameters: urlQueryParams);
|
||||
|
||||
if (queryParams.isNotEmpty) {
|
||||
queryParamExp = declareVar('queryParams').assign(
|
||||
literalMap(queryParams.map((key, value) => MapEntry(key, value))),
|
||||
);
|
||||
|
||||
uriReassignExps = [
|
||||
if (uri.hasQuery)
|
||||
declareVar('urlQueryParams').assign(
|
||||
InvokeExpression.newOf(
|
||||
refer('Map<String,String>'),
|
||||
[refer('uri.queryParameters')],
|
||||
{},
|
||||
[],
|
||||
'from',
|
||||
),
|
||||
),
|
||||
if (uri.hasQuery)
|
||||
refer('urlQueryParams')
|
||||
.property('addAll')
|
||||
.call([refer('queryParams')], {}),
|
||||
refer('uri').assign(refer('uri').property('replace').call([], {
|
||||
'queryParameters':
|
||||
uri.hasQuery ? refer('urlQueryParams') : refer('queryParams'),
|
||||
}))
|
||||
];
|
||||
}
|
||||
|
||||
Expression? headerExp;
|
||||
if (headers.isNotEmpty) {
|
||||
headerExp = declareVar('headers').assign(
|
||||
literalMap(headers.map((key, value) => MapEntry(key, value))),
|
||||
);
|
||||
}
|
||||
final responseExp = declareFinal('response').assign(InvokeExpression.newOf(
|
||||
refer(
|
||||
'http.${method.name}',
|
||||
),
|
||||
[refer('uri')],
|
||||
{
|
||||
if (headerExp != null) 'headers': refer('headers'),
|
||||
if (dataExp != null) 'body': refer('body'),
|
||||
},
|
||||
[],
|
||||
).awaited);
|
||||
final multiPartRequest =
|
||||
declareFinal('request').assign(InvokeExpression.newOf(
|
||||
refer(
|
||||
'http.MultipartRequest',
|
||||
),
|
||||
[refer(jsonEncode(method.name.toUpperCase())), refer('uri')],
|
||||
));
|
||||
final multiPartFiles = declareFinal('formDataList').assign(refer(
|
||||
jsonEncode(formData),
|
||||
));
|
||||
|
||||
final addHeaders = refer('request.headers.addAll').call([refer('headers')]);
|
||||
const multiPartList = Code('''
|
||||
for (Map<String, String> formData in formDataList){
|
||||
if (formData['type'] == 'text') {
|
||||
request.fields.addAll({formData['name']: formData['value']});
|
||||
} else {
|
||||
request.files.add(
|
||||
await http.MultipartFile.fromPath(
|
||||
formData['name'],
|
||||
formData['value'],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
''');
|
||||
var multiPartRequestSend =
|
||||
declareFinal('response').assign(refer('request.send()').awaited);
|
||||
var multiPartResponseBody = declareFinal('responseBody')
|
||||
.assign(refer('response.stream.bytesToString()').awaited);
|
||||
final mainFunction = Method((m) {
|
||||
final statusRef = refer('statusCode');
|
||||
m
|
||||
..name = 'main'
|
||||
..returns = refer('void')
|
||||
..modifier = MethodModifier.async
|
||||
..body = Block((b) {
|
||||
b.statements.add(uriExp.statement);
|
||||
if (queryParamExp != null) {
|
||||
b.statements.add(const Code('\n'));
|
||||
b.statements.add(queryParamExp.statement);
|
||||
}
|
||||
if (uriReassignExps != null) {
|
||||
b.statements.addAll(uriReassignExps.map((e) => e.statement));
|
||||
}
|
||||
if (dataExp != null) {
|
||||
b.statements.add(const Code('\n'));
|
||||
b.statements.add(dataExp.statement);
|
||||
}
|
||||
if (headerExp != null) {
|
||||
b.statements.add(const Code('\n'));
|
||||
b.statements.add(headerExp.statement);
|
||||
}
|
||||
b.statements.add(const Code('\n'));
|
||||
if (contentType == ContentType.formdata) {
|
||||
if (formData.isNotEmpty) {
|
||||
b.statements.add(multiPartFiles.statement);
|
||||
}
|
||||
b.statements.add(multiPartRequest.statement);
|
||||
if (formData.isNotEmpty) {
|
||||
b.statements.add(multiPartList);
|
||||
}
|
||||
if (headerExp != null) {
|
||||
b.statements.add(addHeaders.statement);
|
||||
}
|
||||
b.statements.add(multiPartRequestSend.statement);
|
||||
b.statements.add(multiPartResponseBody.statement);
|
||||
b.statements.add(declareVar('statusCode', type: refer('int'))
|
||||
.assign(refer('response').property('statusCode'))
|
||||
.statement);
|
||||
b.statements.add(const Code('\n'));
|
||||
} else {
|
||||
b.statements.add(responseExp.statement);
|
||||
b.statements.add(const Code('\n'));
|
||||
b.statements.add(declareVar('statusCode', type: refer('int'))
|
||||
.assign(refer('response').property('statusCode'))
|
||||
.statement);
|
||||
}
|
||||
|
||||
b.statements.add(declareIfElse(
|
||||
condition: statusRef
|
||||
.greaterOrEqualTo(literalNum(200))
|
||||
.and(statusRef.lessThan(literalNum(300))),
|
||||
body: [
|
||||
refer('print').call([literalString(r'Status Code: $statusCode')]),
|
||||
refer('print').call([
|
||||
literalString(
|
||||
'Response Body: ${contentType == ContentType.formdata ? ':\$responseBody' : '\${response.body}'}')
|
||||
]),
|
||||
],
|
||||
elseBody: [
|
||||
refer('print')
|
||||
.call([literalString(r'Error Status Code: $statusCode')]),
|
||||
refer('print').call([
|
||||
literalString(
|
||||
'Error Response Body: ${contentType == ContentType.formdata ? ':\$responseBody' : '\${response.body}'}')
|
||||
]),
|
||||
],
|
||||
));
|
||||
});
|
||||
});
|
||||
|
||||
sbf.writeln(mainFunction.accept(emitter));
|
||||
|
||||
return DartFormatter(
|
||||
pageWidth: contentType == ContentType.formdata ? 70 : 160)
|
||||
.format(sbf.toString());
|
||||
}
|
||||
}
|
||||
|
52
lib/codegen/dart/shared.dart
Normal file
52
lib/codegen/dart/shared.dart
Normal file
@ -0,0 +1,52 @@
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
|
||||
Code _toStatement(Spec spec) {
|
||||
if (spec is Expression) {
|
||||
return spec.statement;
|
||||
} else if (spec is Code) {
|
||||
return spec;
|
||||
} else {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
Block declareTryCatch({
|
||||
required List<Spec> body,
|
||||
required Map<String?, List<Spec>> onError,
|
||||
bool showStackStrace = false,
|
||||
}) {
|
||||
return Block((b) {
|
||||
b.statements.add(const Code('try'));
|
||||
b.statements.add(const Code('{'));
|
||||
b.statements.addAll(body.map(_toStatement).toList());
|
||||
final entries = onError.entries;
|
||||
|
||||
for (var error in entries) {
|
||||
b.statements.add(const Code('}'));
|
||||
if (error.key != null) {
|
||||
b.statements.add(Code('on ${error.key}'));
|
||||
}
|
||||
b.statements.add(Code(showStackStrace ? 'catch(e,s)' : 'catch(e)'));
|
||||
|
||||
b.statements.add(const Code('{'));
|
||||
b.statements.addAll(error.value.map(_toStatement).toList());
|
||||
if (entries.last.key == error.key) b.statements.add(const Code('}'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Block declareIfElse({
|
||||
required Expression condition,
|
||||
required List<Spec> body,
|
||||
required List<Spec> elseBody,
|
||||
}) {
|
||||
return Block.of([
|
||||
const Code('if('),
|
||||
condition.code,
|
||||
const Code('){'),
|
||||
...body.map(_toStatement),
|
||||
const Code('} else {'),
|
||||
...elseBody.map(_toStatement),
|
||||
const Code('}'),
|
||||
]);
|
||||
}
|
@ -1,16 +1,18 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:jinja/jinja.dart' as jj;
|
||||
import 'package:apidash/utils/utils.dart'
|
||||
show requestModelToHARJsonRequest, padMultilineString, stripUrlParams;
|
||||
show padMultilineString, requestModelToHARJsonRequest, stripUrlParams;
|
||||
import 'package:apidash/models/models.dart' show RequestModel;
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class AxiosCodeGen {
|
||||
AxiosCodeGen({this.isNodeJs = false});
|
||||
|
||||
final bool isNodeJs;
|
||||
|
||||
String kStringImportNode = """import axios from 'axios';
|
||||
String kStringImportNode = """{% if isNodeJs %}import axios from 'axios';
|
||||
|
||||
{% endif %}{% if isFormDataRequest and isNodeJs %}const fs = require('fs');{% endif %}
|
||||
""";
|
||||
|
||||
String kTemplateStart = """let config = {
|
||||
@ -46,13 +48,49 @@ axios(config)
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
String kMultiPartBodyTemplate = r'''
|
||||
|
||||
|
||||
async function buildFormData(fields) {
|
||||
var formdata = new FormData();
|
||||
for (const field of fields) {
|
||||
const name = field.name || '';
|
||||
const value = field.value || '';
|
||||
const type = field.type || 'text';
|
||||
|
||||
if (type === 'text') {
|
||||
formdata.append(name, value);
|
||||
} else if (type === 'file') {
|
||||
formdata.append(name,{% if isNodeJs %} fs.createReadStream(value){% else %} fileInput.files[0],value{% endif %});
|
||||
}
|
||||
}
|
||||
return formdata;
|
||||
}
|
||||
|
||||
|
||||
''';
|
||||
var kGetFormDataTemplate = '''buildFormData({{fields_list}});
|
||||
''';
|
||||
String? getCode(
|
||||
RequestModel requestModel,
|
||||
String defaultUriScheme,
|
||||
) {
|
||||
try {
|
||||
String result = isNodeJs ? kStringImportNode : "";
|
||||
jj.Template kNodejsImportTemplate = jj.Template(kStringImportNode);
|
||||
String importsData = kNodejsImportTemplate.render({
|
||||
"isFormDataRequest": requestModel.isFormDataRequest,
|
||||
"isNodeJs": isNodeJs,
|
||||
});
|
||||
|
||||
String result = importsData;
|
||||
if (requestModel.isFormDataRequest &&
|
||||
requestModel.formDataMapList.isNotEmpty) {
|
||||
var templateMultiPartBody = jj.Template(kMultiPartBodyTemplate);
|
||||
var renderedMultiPartBody = templateMultiPartBody.render({
|
||||
"isNodeJs": isNodeJs,
|
||||
});
|
||||
result += renderedMultiPartBody;
|
||||
}
|
||||
|
||||
String url = requestModel.url;
|
||||
if (!url.contains("://") && url.isNotEmpty) {
|
||||
@ -60,7 +98,7 @@ axios(config)
|
||||
}
|
||||
var rM = requestModel.copyWith(url: url);
|
||||
|
||||
var harJson = requestModelToHARJsonRequest(rM);
|
||||
var harJson = requestModelToHARJsonRequest(rM, useEnabled: true);
|
||||
|
||||
var templateStart = jj.Template(kTemplateStart);
|
||||
result += templateStart.render({
|
||||
@ -80,18 +118,31 @@ axios(config)
|
||||
}
|
||||
|
||||
var headers = harJson["headers"];
|
||||
if (headers.isNotEmpty) {
|
||||
if (headers.isNotEmpty || requestModel.isFormDataRequest) {
|
||||
var templateHeader = jj.Template(kTemplateHeader);
|
||||
var m = {};
|
||||
for (var i in headers) {
|
||||
m[i["name"]] = i["value"];
|
||||
}
|
||||
if (requestModel.isFormDataRequest) {
|
||||
m['Content-Type'] = 'multipart/form-data';
|
||||
}
|
||||
result += templateHeader
|
||||
.render({"headers": padMultilineString(kEncoder.convert(m), 2)});
|
||||
}
|
||||
|
||||
if (harJson["postData"]?["text"] != null) {
|
||||
var templateBody = jj.Template(kTemplateBody);
|
||||
|
||||
if (requestModel.isFormDataRequest &&
|
||||
requestModel.formDataMapList.isNotEmpty) {
|
||||
var getFieldDataTemplate = jj.Template(kGetFormDataTemplate);
|
||||
|
||||
result += templateBody.render({
|
||||
"body": getFieldDataTemplate.render({
|
||||
"fields_list": json.encode(requestModel.formDataMapList),
|
||||
})
|
||||
});
|
||||
}
|
||||
if (harJson["postData"]?["text"] != null) {
|
||||
result += templateBody
|
||||
.render({"body": kEncoder.convert(harJson["postData"]["text"])});
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:jinja/jinja.dart' as jj;
|
||||
import 'package:apidash/utils/utils.dart'
|
||||
show requestModelToHARJsonRequest, padMultilineString;
|
||||
show padMultilineString, requestModelToHARJsonRequest;
|
||||
import 'package:apidash/models/models.dart' show RequestModel;
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class FetchCodeGen {
|
||||
FetchCodeGen({this.isNodeJs = false});
|
||||
|
||||
final bool isNodeJs;
|
||||
|
||||
String kStringImportNode = """import fetch from 'node-fetch';
|
||||
String kStringImportNode = """
|
||||
import fetch from 'node-fetch';
|
||||
{% if isFormDataRequest %}const fs = require('fs');{% endif %}
|
||||
|
||||
""";
|
||||
|
||||
@ -28,6 +31,26 @@ let options = {
|
||||
{{body}}
|
||||
""";
|
||||
|
||||
String kMultiPartBodyTemplate = r'''
|
||||
async function buildDataList(fields) {
|
||||
var formdata = new FormData();
|
||||
for (const field of fields) {
|
||||
const name = field.name || '';
|
||||
const value = field.value || '';
|
||||
const type = field.type || 'text';
|
||||
|
||||
if (type === 'text') {
|
||||
formdata.append(name, value);
|
||||
} else if (type === 'file') {
|
||||
formdata.append(name,{% if isNodeJs %} fs.createReadStream(value){% else %} fileInput.files[0],value{% endif %});
|
||||
}
|
||||
}
|
||||
return formdata;
|
||||
}
|
||||
|
||||
const payload = buildDataList({{fields_list}});
|
||||
|
||||
''';
|
||||
String kStringRequest = """
|
||||
|
||||
};
|
||||
@ -53,15 +76,26 @@ fetch(url, options)
|
||||
String defaultUriScheme,
|
||||
) {
|
||||
try {
|
||||
String result = isNodeJs ? kStringImportNode : "";
|
||||
jj.Template kNodejsImportTemplate = jj.Template(kStringImportNode);
|
||||
String importsData = kNodejsImportTemplate.render({
|
||||
"isFormDataRequest": requestModel.isFormDataRequest,
|
||||
});
|
||||
|
||||
String result = isNodeJs ? importsData : "";
|
||||
if (requestModel.isFormDataRequest) {
|
||||
var templateMultiPartBody = jj.Template(kMultiPartBodyTemplate);
|
||||
result += templateMultiPartBody.render({
|
||||
"isNodeJs": isNodeJs,
|
||||
"fields_list": json.encode(requestModel.formDataMapList),
|
||||
});
|
||||
}
|
||||
String url = requestModel.url;
|
||||
if (!url.contains("://") && url.isNotEmpty) {
|
||||
url = "$defaultUriScheme://$url";
|
||||
}
|
||||
var rM = requestModel.copyWith(url: url);
|
||||
|
||||
var harJson = requestModelToHARJsonRequest(rM);
|
||||
var harJson = requestModelToHARJsonRequest(rM, useEnabled: true);
|
||||
|
||||
var templateStart = jj.Template(kTemplateStart);
|
||||
result += templateStart.render({
|
||||
@ -70,21 +104,33 @@ fetch(url, options)
|
||||
});
|
||||
|
||||
var headers = harJson["headers"];
|
||||
|
||||
if (headers.isNotEmpty) {
|
||||
var templateHeader = jj.Template(kTemplateHeader);
|
||||
var m = {};
|
||||
if (requestModel.isFormDataRequest) {
|
||||
m["Content-Type"] = "multipart/form-data";
|
||||
}
|
||||
for (var i in headers) {
|
||||
m[i["name"]] = i["value"];
|
||||
}
|
||||
result += templateHeader
|
||||
.render({"headers": padMultilineString(kEncoder.convert(m), 2)});
|
||||
result += templateHeader.render({
|
||||
"headers": padMultilineString(kEncoder.convert(m), 2),
|
||||
});
|
||||
}
|
||||
|
||||
if (harJson["postData"]?["text"] != null) {
|
||||
var templateBody = jj.Template(kTemplateBody);
|
||||
result += templateBody
|
||||
.render({"body": kEncoder.convert(harJson["postData"]["text"])});
|
||||
result += templateBody.render({
|
||||
"body": kEncoder.convert(harJson["postData"]["text"]),
|
||||
});
|
||||
} else if (requestModel.isFormDataRequest) {
|
||||
var templateBody = jj.Template(kTemplateBody);
|
||||
result += templateBody.render({
|
||||
"body": 'payload',
|
||||
});
|
||||
}
|
||||
|
||||
result += kStringRequest;
|
||||
return result;
|
||||
} catch (e) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import 'dart:convert';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:jinja/jinja.dart' as jj;
|
||||
import 'package:apidash/utils/utils.dart'
|
||||
show getValidRequestUri, stripUriParams;
|
||||
import '../../models/request_model.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class KotlinOkHttpCodeGen {
|
||||
final String kTemplateStart = """import okhttp3.OkHttpClient
|
||||
@ -61,6 +61,13 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
||||
}
|
||||
|
||||
""";
|
||||
// Converting list of form data objects to kolin multi part data
|
||||
String kFormDataBody = '''
|
||||
val body = MultipartBody.Builder().setType(MultipartBody.FORM){% for item in formDataList %}{% if item.type == 'file' %}
|
||||
.addFormDataPart("{{item.name}}",null,File("{{item.value}}").asRequestBody("application/octet-stream".toMediaType()))
|
||||
{% else %}.addFormDataPart("{{item.name}}","{{item.value}}")
|
||||
{% endif %}{% endfor %}.build()
|
||||
''';
|
||||
|
||||
String? getCode(
|
||||
RequestModel requestModel,
|
||||
@ -68,7 +75,6 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
||||
) {
|
||||
try {
|
||||
String result = "";
|
||||
bool hasHeaders = false;
|
||||
bool hasQuery = false;
|
||||
bool hasBody = false;
|
||||
|
||||
@ -77,7 +83,10 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
||||
url = "$defaultUriScheme://$url";
|
||||
}
|
||||
|
||||
var rec = getValidRequestUri(url, requestModel.requestParams);
|
||||
var rec = getValidRequestUri(
|
||||
url,
|
||||
requestModel.enabledRequestParams,
|
||||
);
|
||||
Uri? uri = rec.$1;
|
||||
|
||||
if (uri != null) {
|
||||
@ -99,12 +108,17 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
||||
|
||||
var method = requestModel.method;
|
||||
var requestBody = requestModel.requestBody;
|
||||
if (kMethodsWithBody.contains(method) && requestBody != null) {
|
||||
if (requestModel.isFormDataRequest) {
|
||||
var formDataTemplate = jj.Template(kFormDataBody);
|
||||
|
||||
result += formDataTemplate.render({
|
||||
"formDataList": requestModel.formDataMapList,
|
||||
});
|
||||
} else if (kMethodsWithBody.contains(method) && requestBody != null) {
|
||||
var contentLength = utf8.encode(requestBody).length;
|
||||
if (contentLength > 0) {
|
||||
hasBody = true;
|
||||
String contentType =
|
||||
kContentTypeMap[requestModel.requestBodyContentType] ?? "";
|
||||
String contentType = requestModel.requestBodyContentType.header;
|
||||
var templateBody = jj.Template(kTemplateRequestBody);
|
||||
result += templateBody
|
||||
.render({"contentType": contentType, "body": requestBody});
|
||||
@ -120,11 +134,10 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
||||
result = stringStart + result;
|
||||
result += kStringRequestStart;
|
||||
|
||||
var headersList = requestModel.requestHeaders;
|
||||
var headersList = requestModel.enabledRequestHeaders;
|
||||
if (headersList != null) {
|
||||
var headers = requestModel.headersMap;
|
||||
var headers = requestModel.enabledHeadersMap;
|
||||
if (headers.isNotEmpty) {
|
||||
hasHeaders = true;
|
||||
result += getHeaders(headers);
|
||||
}
|
||||
}
|
||||
@ -132,7 +145,7 @@ import okhttp3.MediaType.Companion.toMediaType""";
|
||||
var templateRequestEnd = jj.Template(kTemplateRequestEnd);
|
||||
result += templateRequestEnd.render({
|
||||
"method": method.name.toLowerCase(),
|
||||
"hasBody": hasBody ? "body" : "",
|
||||
"hasBody": (hasBody || requestModel.isFormDataRequest) ? "body" : "",
|
||||
});
|
||||
}
|
||||
return result;
|
||||
|
@ -10,6 +10,9 @@ class cURLCodeGen {
|
||||
String kTemplateHeader = """ \\
|
||||
--header '{{name}}: {{value}}'
|
||||
""";
|
||||
String kTemplateFormData = """ \\
|
||||
--form '{{name}}: {{value}}'
|
||||
""";
|
||||
|
||||
String kTemplateBody = """ \\
|
||||
--data '{{body}}'
|
||||
@ -28,7 +31,7 @@ class cURLCodeGen {
|
||||
}
|
||||
var rM = requestModel.copyWith(url: url);
|
||||
|
||||
var harJson = requestModelToHARJsonRequest(rM);
|
||||
var harJson = requestModelToHARJsonRequest(rM, useEnabled: true);
|
||||
|
||||
var templateStart = jj.Template(kTemplateStart);
|
||||
result += templateStart.render({
|
||||
@ -48,6 +51,23 @@ class cURLCodeGen {
|
||||
.render({"name": item["name"], "value": item["value"]});
|
||||
}
|
||||
}
|
||||
if (harJson['formData'] != null) {
|
||||
var formDataList = harJson['formData'] as List<Map<String, dynamic>>;
|
||||
for (var formData in formDataList) {
|
||||
var templateFormData = jj.Template(kTemplateFormData);
|
||||
if (formData['type'] != null &&
|
||||
formData['name'] != null &&
|
||||
formData['value'] != null &&
|
||||
formData['name']!.isNotEmpty &&
|
||||
formData['value']!.isNotEmpty) {
|
||||
result += templateFormData.render({
|
||||
"name": formData["name"],
|
||||
"value":
|
||||
"${formData['type'] == 'file' ? '@' : ''}${formData["value"]}",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (harJson["postData"]?["text"] != null) {
|
||||
var templateBody = jj.Template(kTemplateBody);
|
||||
|
@ -10,7 +10,9 @@ class HARCodeGen {
|
||||
try {
|
||||
var harString = kEncoder.convert(requestModelToHARJsonRequest(
|
||||
requestModel,
|
||||
defaultUriScheme: defaultUriScheme));
|
||||
defaultUriScheme: defaultUriScheme,
|
||||
useEnabled: true,
|
||||
));
|
||||
return harString;
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
@ -1,13 +1,16 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:jinja/jinja.dart' as jj;
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/utils/utils.dart'
|
||||
show getValidRequestUri, padMultilineString;
|
||||
show getNewUuid, getValidRequestUri, padMultilineString;
|
||||
import 'package:apidash/models/models.dart' show RequestModel;
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class PythonHttpClientCodeGen {
|
||||
final String kTemplateStart = """import http.client
|
||||
{% if isFormDataRequest %}import mimetypes
|
||||
from codecs import encode
|
||||
{% endif %}
|
||||
""";
|
||||
|
||||
String kTemplateParams = """
|
||||
@ -30,6 +33,8 @@ body = r'''{{body}}'''
|
||||
headers = {{headers}}
|
||||
|
||||
""";
|
||||
String kTemplateFormHeaderContentType = '''
|
||||
multipart/form-data; boundary={{boundary}}''';
|
||||
|
||||
int kHeadersPadding = 10;
|
||||
|
||||
@ -55,10 +60,38 @@ data = res.read()
|
||||
print(data.decode("utf-8"))
|
||||
""";
|
||||
|
||||
final String kStringFormDataBody = r'''
|
||||
|
||||
def build_data_list(fields):
|
||||
dataList = []
|
||||
for field in fields:
|
||||
name = field.get('name', '')
|
||||
value = field.get('value', '')
|
||||
type_ = field.get('type', 'text')
|
||||
dataList.append(encode('--{{boundary}}'))
|
||||
if type_ == 'text':
|
||||
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"'))
|
||||
dataList.append(encode('Content-Type: text/plain'))
|
||||
dataList.append(encode(''))
|
||||
dataList.append(encode(value))
|
||||
elif type_ == 'file':
|
||||
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"; filename="{value}"'))
|
||||
dataList.append(encode(f'Content-Type: {mimetypes.guess_type(value)[0] or "application/octet-stream"}'))
|
||||
dataList.append(encode(''))
|
||||
dataList.append(open(value, 'rb').read())
|
||||
dataList.append(encode(f'--{{boundary}}--'))
|
||||
dataList.append(encode(''))
|
||||
return dataList
|
||||
|
||||
dataList = build_data_list({{fields_list}})
|
||||
body = b'\r\n'.join(dataList)
|
||||
''';
|
||||
String? getCode(
|
||||
RequestModel requestModel,
|
||||
String defaultUriScheme,
|
||||
) {
|
||||
String uuid = getNewUuid();
|
||||
|
||||
try {
|
||||
String result = "";
|
||||
bool hasHeaders = false;
|
||||
@ -70,8 +103,17 @@ print(data.decode("utf-8"))
|
||||
url = "$defaultUriScheme://$url";
|
||||
}
|
||||
|
||||
result += kTemplateStart;
|
||||
var rec = getValidRequestUri(url, requestModel.requestParams);
|
||||
var templateStartUrl = jj.Template(kTemplateStart);
|
||||
result += templateStartUrl.render(
|
||||
{
|
||||
"isFormDataRequest": requestModel.isFormDataRequest,
|
||||
},
|
||||
);
|
||||
var rec = getValidRequestUri(
|
||||
url,
|
||||
requestModel.enabledRequestParams,
|
||||
);
|
||||
|
||||
Uri? uri = rec.$1;
|
||||
|
||||
if (uri != null) {
|
||||
@ -97,14 +139,22 @@ print(data.decode("utf-8"))
|
||||
}
|
||||
}
|
||||
|
||||
var headersList = requestModel.requestHeaders;
|
||||
var headersList = requestModel.enabledRequestHeaders;
|
||||
if (headersList != null || hasBody) {
|
||||
var headers = requestModel.headersMap;
|
||||
var headers = requestModel.enabledHeadersMap;
|
||||
if (requestModel.isFormDataRequest) {
|
||||
var formHeaderTemplate =
|
||||
jj.Template(kTemplateFormHeaderContentType);
|
||||
headers[HttpHeaders.contentTypeHeader] = formHeaderTemplate.render({
|
||||
"boundary": uuid,
|
||||
});
|
||||
}
|
||||
|
||||
if (headers.isNotEmpty || hasBody) {
|
||||
hasHeaders = true;
|
||||
if (hasBody) {
|
||||
if (hasBody && !requestModel.hasContentTypeHeader) {
|
||||
headers[HttpHeaders.contentTypeHeader] =
|
||||
kContentTypeMap[requestModel.requestBodyContentType] ?? "";
|
||||
requestModel.requestBodyContentType.header;
|
||||
}
|
||||
var headersString = kEncoder.convert(headers);
|
||||
headersString = padMultilineString(headersString, kHeadersPadding);
|
||||
@ -112,7 +162,15 @@ print(data.decode("utf-8"))
|
||||
result += templateHeaders.render({"headers": headersString});
|
||||
}
|
||||
}
|
||||
|
||||
if (requestModel.isFormDataRequest) {
|
||||
var formDataBodyData = jj.Template(kStringFormDataBody);
|
||||
result += formDataBodyData.render(
|
||||
{
|
||||
"fields_list": json.encode(requestModel.formDataMapList),
|
||||
"boundary": uuid,
|
||||
},
|
||||
);
|
||||
}
|
||||
var templateConnection = jj.Template(kTemplateConnection);
|
||||
result += templateConnection.render({
|
||||
"isHttps": uri.scheme == "https" ? "S" : "",
|
||||
@ -126,11 +184,11 @@ print(data.decode("utf-8"))
|
||||
"queryParamsStr": hasQuery ? " + queryParamsStr" : "",
|
||||
});
|
||||
|
||||
if (hasBody) {
|
||||
if (hasBody || requestModel.isFormDataRequest) {
|
||||
result += kStringRequestBody;
|
||||
}
|
||||
|
||||
if (hasHeaders) {
|
||||
if (hasHeaders || requestModel.isFormDataRequest) {
|
||||
result += kStringRequestHeaders;
|
||||
}
|
||||
|
||||
|
@ -3,12 +3,14 @@ import 'dart:convert';
|
||||
import 'package:jinja/jinja.dart' as jj;
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/utils/utils.dart'
|
||||
show getValidRequestUri, padMultilineString, stripUriParams;
|
||||
show getNewUuid, getValidRequestUri, padMultilineString, stripUriParams;
|
||||
import 'package:apidash/models/models.dart' show RequestModel;
|
||||
|
||||
class PythonRequestsCodeGen {
|
||||
final String kTemplateStart = """import requests
|
||||
|
||||
{% if isFormDataRequest %}import mimetypes
|
||||
from codecs import encode
|
||||
{% endif %}
|
||||
url = '{{url}}'
|
||||
|
||||
""";
|
||||
@ -37,6 +39,8 @@ payload = {{body}}
|
||||
headers = {{headers}}
|
||||
|
||||
""";
|
||||
String kTemplateFormHeaderContentType = '''
|
||||
multipart/form-data; boundary={{boundary}}''';
|
||||
|
||||
int kHeadersPadding = 10;
|
||||
|
||||
@ -45,6 +49,34 @@ headers = {{headers}}
|
||||
response = requests.{{method}}(url
|
||||
""";
|
||||
|
||||
final String kStringFormDataBody = r'''
|
||||
|
||||
def build_data_list(fields):
|
||||
dataList = []
|
||||
for field in fields:
|
||||
name = field.get('name', '')
|
||||
value = field.get('value', '')
|
||||
type_ = field.get('type', 'text')
|
||||
|
||||
dataList.append(encode('--{{boundary}}'))
|
||||
if type_ == 'text':
|
||||
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"'))
|
||||
dataList.append(encode('Content-Type: text/plain'))
|
||||
dataList.append(encode(''))
|
||||
dataList.append(encode(value))
|
||||
elif type_ == 'file':
|
||||
dataList.append(encode(f'Content-Disposition: form-data; name="{name}"; filename="{value}"'))
|
||||
dataList.append(encode(f'Content-Type: {mimetypes.guess_type(value)[0] or "application/octet-stream"}'))
|
||||
dataList.append(encode(''))
|
||||
dataList.append(open(value, 'rb').read())
|
||||
dataList.append(encode('--{{boundary}}--'))
|
||||
dataList.append(encode(''))
|
||||
return dataList
|
||||
|
||||
dataList = build_data_list({{fields_list}})
|
||||
payload = b'\r\n'.join(dataList)
|
||||
''';
|
||||
|
||||
String kStringRequestParams = """, params=params""";
|
||||
|
||||
String kStringRequestBody = """, data=payload""";
|
||||
@ -69,17 +101,24 @@ print('Response Body:', response.text)
|
||||
bool hasHeaders = false;
|
||||
bool hasBody = false;
|
||||
bool hasJsonBody = false;
|
||||
String uuid = getNewUuid();
|
||||
|
||||
String url = requestModel.url;
|
||||
if (!url.contains("://") && url.isNotEmpty) {
|
||||
url = "$defaultUriScheme://$url";
|
||||
}
|
||||
|
||||
var rec = getValidRequestUri(url, requestModel.requestParams);
|
||||
var rec = getValidRequestUri(
|
||||
url,
|
||||
requestModel.enabledRequestParams,
|
||||
);
|
||||
Uri? uri = rec.$1;
|
||||
if (uri != null) {
|
||||
var templateStartUrl = jj.Template(kTemplateStart);
|
||||
result += templateStartUrl.render({"url": stripUriParams(uri)});
|
||||
result += templateStartUrl.render({
|
||||
"url": stripUriParams(uri),
|
||||
'isFormDataRequest': requestModel.isFormDataRequest
|
||||
});
|
||||
|
||||
if (uri.hasQuery) {
|
||||
var params = uri.queryParameters;
|
||||
@ -109,14 +148,21 @@ print('Response Body:', response.text)
|
||||
}
|
||||
}
|
||||
|
||||
var headersList = requestModel.requestHeaders;
|
||||
var headersList = requestModel.enabledRequestHeaders;
|
||||
if (headersList != null || hasBody) {
|
||||
var headers = requestModel.headersMap;
|
||||
var headers = requestModel.enabledHeadersMap;
|
||||
if (requestModel.isFormDataRequest) {
|
||||
var formHeaderTemplate =
|
||||
jj.Template(kTemplateFormHeaderContentType);
|
||||
headers[HttpHeaders.contentTypeHeader] = formHeaderTemplate.render({
|
||||
"boundary": uuid,
|
||||
});
|
||||
}
|
||||
if (headers.isNotEmpty || hasBody) {
|
||||
hasHeaders = true;
|
||||
if (hasBody) {
|
||||
headers[HttpHeaders.contentTypeHeader] =
|
||||
kContentTypeMap[requestModel.requestBodyContentType] ?? "";
|
||||
requestModel.requestBodyContentType.header;
|
||||
}
|
||||
var headersString = kEncoder.convert(headers);
|
||||
headersString = padMultilineString(headersString, kHeadersPadding);
|
||||
@ -124,7 +170,15 @@ print('Response Body:', response.text)
|
||||
result += templateHeaders.render({"headers": headersString});
|
||||
}
|
||||
}
|
||||
|
||||
if (requestModel.isFormDataRequest) {
|
||||
var formDataBodyData = jj.Template(kStringFormDataBody);
|
||||
result += formDataBodyData.render(
|
||||
{
|
||||
"fields_list": json.encode(requestModel.formDataMapList),
|
||||
"boundary": uuid,
|
||||
},
|
||||
);
|
||||
}
|
||||
var templateRequest = jj.Template(kTemplateRequest);
|
||||
result += templateRequest.render({
|
||||
"method": method.name.toLowerCase(),
|
||||
@ -134,15 +188,15 @@ print('Response Body:', response.text)
|
||||
result += kStringRequestParams;
|
||||
}
|
||||
|
||||
if (hasBody) {
|
||||
if (hasBody || requestModel.isFormDataRequest) {
|
||||
result += kStringRequestBody;
|
||||
}
|
||||
|
||||
if (hasJsonBody) {
|
||||
if (hasJsonBody || requestModel.isFormDataRequest) {
|
||||
result += kStringRequestJson;
|
||||
}
|
||||
|
||||
if (hasHeaders) {
|
||||
if (hasHeaders || requestModel.isFormDataRequest) {
|
||||
result += kStringRequestHeaders;
|
||||
}
|
||||
|
||||
|
20
lib/common/utils.dart
Normal file
20
lib/common/utils.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/utils/utils.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
|
||||
Future<void> saveCollection(
|
||||
Map<String, dynamic> data, ScaffoldMessengerState sm) async {
|
||||
var message = "";
|
||||
try {
|
||||
var pth = await getFileDownloadpath(null, "har");
|
||||
if (pth != null) {
|
||||
await saveFile(pth, jsonMapToBytes(data));
|
||||
var sp = getShortPath(pth);
|
||||
message = 'Saved to $sp';
|
||||
}
|
||||
} catch (e) {
|
||||
message = "An error occurred while exporting.";
|
||||
}
|
||||
sm.hideCurrentSnackBar();
|
||||
sm.showSnackBar(getSnackBar(message, small: false));
|
||||
}
|
@ -16,6 +16,10 @@ final kIsApple = !kIsWeb && (Platform.isIOS || Platform.isMacOS);
|
||||
final kIsDesktop =
|
||||
!kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux);
|
||||
|
||||
final kIsIOS = !kIsWeb && Platform.isIOS;
|
||||
final kIsAndroid = !kIsWeb && Platform.isAndroid;
|
||||
final kIsMobile = !kIsWeb && (Platform.isIOS || Platform.isAndroid);
|
||||
|
||||
final kColorTransparentState =
|
||||
MaterialStateProperty.all<Color>(Colors.transparent);
|
||||
const kColorTransparent = Colors.transparent;
|
||||
@ -44,6 +48,11 @@ const kHintOpacity = 0.6;
|
||||
const kForegroundOpacity = 0.05;
|
||||
|
||||
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
|
||||
const kTextStyleButtonSmall = TextStyle(fontSize: 12);
|
||||
const kFormDataButtonLabelTextStyle = TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
const kBorderRadius8 = BorderRadius.all(Radius.circular(8));
|
||||
final kBorderRadius10 = BorderRadius.circular(10);
|
||||
@ -53,22 +62,36 @@ const kP1 = EdgeInsets.all(1);
|
||||
const kP5 = EdgeInsets.all(5);
|
||||
const kP8 = EdgeInsets.all(8);
|
||||
const kPs8 = EdgeInsets.only(left: 8);
|
||||
const kPs2 = EdgeInsets.only(left: 2);
|
||||
const kPh20v5 = EdgeInsets.symmetric(horizontal: 20, vertical: 5);
|
||||
const kPh20v10 = EdgeInsets.symmetric(horizontal: 20, vertical: 10);
|
||||
const kP10 = EdgeInsets.all(10);
|
||||
const kPt24o8 = EdgeInsets.only(top: 24, left: 8.0, right: 8.0, bottom: 8.0);
|
||||
const kPt5o10 =
|
||||
EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 10.0);
|
||||
const kPh20 = EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
);
|
||||
const kPh20t40 = EdgeInsets.only(
|
||||
left: 20,
|
||||
right: 20,
|
||||
top: 40,
|
||||
);
|
||||
const kPh60 = EdgeInsets.symmetric(horizontal: 60);
|
||||
const kP24CollectionPane = EdgeInsets.only(top: 24, left: 8.0, bottom: 8.0);
|
||||
const kP8CollectionPane = EdgeInsets.only(top: 8.0, left: 8.0, bottom: 8.0);
|
||||
const kP24CollectionPane = EdgeInsets.only(
|
||||
top: 24,
|
||||
left: 4.0,
|
||||
//right: 4.0,
|
||||
// bottom: 8.0,
|
||||
);
|
||||
const kP8CollectionPane = EdgeInsets.only(
|
||||
top: 8.0,
|
||||
left: 4.0,
|
||||
//right: 4.0,
|
||||
// bottom: 8.0,
|
||||
);
|
||||
const kPr8CollectionPane = EdgeInsets.only(right: 8.0);
|
||||
|
||||
const kpsV5 = EdgeInsets.symmetric(vertical: 2);
|
||||
const kHSpacer4 = SizedBox(width: 4);
|
||||
const kHSpacer5 = SizedBox(width: 5);
|
||||
const kHSpacer10 = SizedBox(width: 10);
|
||||
@ -220,7 +243,7 @@ enum RequestItemMenuOption { edit, delete, duplicate }
|
||||
|
||||
enum HTTPVerb { get, head, post, put, patch, delete }
|
||||
|
||||
enum ContentType { json, text }
|
||||
enum FormDataType { text, file }
|
||||
|
||||
const kSupportedUriSchemes = ["https", "http"];
|
||||
const kDefaultUriScheme = "https";
|
||||
@ -238,6 +261,7 @@ enum CodegenLanguage {
|
||||
curl("cURL", "bash", "curl"),
|
||||
har("HAR", "json", "har"),
|
||||
dartHttp("Dart (http)", "dart", "dart"),
|
||||
dartDio("Dart (dio)", "dart", "dart"),
|
||||
jsAxios("JavaScript (axios)", "javascript", "js"),
|
||||
jsFetch("JavaScript (fetch)", "javascript", "js"),
|
||||
nodejsAxios("node.js (axios)", "javascript", "js"),
|
||||
@ -287,24 +311,25 @@ const kTypeVideo = 'video';
|
||||
|
||||
const kSubTypeDefaultViewOptions = 'all';
|
||||
|
||||
const kContentTypeMap = {
|
||||
ContentType.json: "$kTypeApplication/$kSubTypeJson",
|
||||
ContentType.text: "$kTypeText/$kSubTypePlain",
|
||||
};
|
||||
enum ContentType {
|
||||
json("$kTypeApplication/$kSubTypeJson"),
|
||||
text("$kTypeText/$kSubTypePlain"),
|
||||
formdata("multipart/form-data");
|
||||
|
||||
enum ResponseBodyView { preview, code, raw, none }
|
||||
const ContentType(this.header);
|
||||
final String header;
|
||||
}
|
||||
|
||||
const kKeyIcon = "icon";
|
||||
const kKeyName = "name";
|
||||
const Map<ResponseBodyView, Map> kResponseBodyViewIcons = {
|
||||
ResponseBodyView.none: {kKeyName: "Preview", kKeyIcon: Icons.warning},
|
||||
ResponseBodyView.preview: {
|
||||
kKeyName: "Preview",
|
||||
kKeyIcon: Icons.visibility_rounded
|
||||
},
|
||||
ResponseBodyView.code: {kKeyName: "Preview", kKeyIcon: Icons.code_rounded},
|
||||
ResponseBodyView.raw: {kKeyName: "Raw", kKeyIcon: Icons.text_snippet_rounded}
|
||||
};
|
||||
enum ResponseBodyView {
|
||||
preview("Preview", Icons.visibility_rounded),
|
||||
code("Preview", Icons.code_rounded),
|
||||
raw("Raw", Icons.text_snippet_rounded),
|
||||
none("Preview", Icons.warning);
|
||||
|
||||
const ResponseBodyView(this.label, this.icon);
|
||||
final String label;
|
||||
final IconData icon;
|
||||
}
|
||||
|
||||
const kNoBodyViewOptions = [ResponseBodyView.none];
|
||||
const kNoRawBodyViewOptions = [ResponseBodyView.none, ResponseBodyView.raw];
|
||||
@ -338,7 +363,7 @@ const Map<String, Map<String, List<ResponseBodyView>>>
|
||||
},
|
||||
kTypeImage: {
|
||||
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
|
||||
kSubTypeSvg: kCodeRawBodyViewOptions,
|
||||
kSubTypeSvg: kPreviewRawBodyViewOptions,
|
||||
},
|
||||
kTypeAudio: {
|
||||
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
|
||||
@ -455,6 +480,9 @@ const kUnexpectedRaiseIssue =
|
||||
const kImageError =
|
||||
"There seems to be an issue rendering this image. Please raise an issue in API Dash GitHub repo so that we can resolve it.";
|
||||
|
||||
const kSvgError =
|
||||
"There seems to be an issue rendering this SVG image. Please raise an issue in API Dash GitHub repo so that we can resolve it.";
|
||||
|
||||
const kPdfError =
|
||||
"There seems to be an issue rendering this pdf. Please raise an issue in API Dash GitHub repo so that we can resolve it.";
|
||||
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'services/services.dart';
|
||||
import 'consts.dart' show kIsLinux;
|
||||
import 'consts.dart' show kIsLinux, kIsMacOS, kIsWindows;
|
||||
import 'app.dart';
|
||||
|
||||
void main() async {
|
||||
@ -11,13 +11,14 @@ void main() async {
|
||||
await openBoxes();
|
||||
if (kIsLinux) {
|
||||
await setupInitialWindow();
|
||||
} else {
|
||||
}
|
||||
if (kIsMacOS || kIsWindows) {
|
||||
var win = getInitialSize();
|
||||
await setupWindow(sz: win.$1, off: win.$2);
|
||||
}
|
||||
runApp(
|
||||
ProviderScope(
|
||||
child: kIsLinux ? const DashApp() : const App(),
|
||||
const ProviderScope(
|
||||
child: DashApp(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
23
lib/models/form_data_model.dart
Normal file
23
lib/models/form_data_model.dart
Normal file
@ -0,0 +1,23 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'form_data_model.freezed.dart';
|
||||
part 'form_data_model.g.dart';
|
||||
|
||||
@freezed
|
||||
class FormDataModel with _$FormDataModel {
|
||||
const factory FormDataModel({
|
||||
required String name,
|
||||
required String value,
|
||||
required FormDataType type,
|
||||
}) = _FormDataModel;
|
||||
|
||||
factory FormDataModel.fromJson(Map<String, Object?> json) =>
|
||||
_$FormDataModelFromJson(json);
|
||||
}
|
||||
|
||||
const kFormDataEmptyModel = FormDataModel(
|
||||
name: "",
|
||||
value: "",
|
||||
type: FormDataType.text,
|
||||
);
|
187
lib/models/form_data_model.freezed.dart
Normal file
187
lib/models/form_data_model.freezed.dart
Normal file
@ -0,0 +1,187 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'form_data_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
FormDataModel _$FormDataModelFromJson(Map<String, dynamic> json) {
|
||||
return _FormDataModel.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$FormDataModel {
|
||||
String get name => throw _privateConstructorUsedError;
|
||||
String get value => throw _privateConstructorUsedError;
|
||||
FormDataType get type => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$FormDataModelCopyWith<FormDataModel> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $FormDataModelCopyWith<$Res> {
|
||||
factory $FormDataModelCopyWith(
|
||||
FormDataModel value, $Res Function(FormDataModel) then) =
|
||||
_$FormDataModelCopyWithImpl<$Res, FormDataModel>;
|
||||
@useResult
|
||||
$Res call({String name, String value, FormDataType type});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$FormDataModelCopyWithImpl<$Res, $Val extends FormDataModel>
|
||||
implements $FormDataModelCopyWith<$Res> {
|
||||
_$FormDataModelCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? name = null,
|
||||
Object? value = null,
|
||||
Object? type = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
value: null == value
|
||||
? _value.value
|
||||
: value // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as FormDataType,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FormDataModelImplCopyWith<$Res>
|
||||
implements $FormDataModelCopyWith<$Res> {
|
||||
factory _$$FormDataModelImplCopyWith(
|
||||
_$FormDataModelImpl value, $Res Function(_$FormDataModelImpl) then) =
|
||||
__$$FormDataModelImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({String name, String value, FormDataType type});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FormDataModelImplCopyWithImpl<$Res>
|
||||
extends _$FormDataModelCopyWithImpl<$Res, _$FormDataModelImpl>
|
||||
implements _$$FormDataModelImplCopyWith<$Res> {
|
||||
__$$FormDataModelImplCopyWithImpl(
|
||||
_$FormDataModelImpl _value, $Res Function(_$FormDataModelImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? name = null,
|
||||
Object? value = null,
|
||||
Object? type = null,
|
||||
}) {
|
||||
return _then(_$FormDataModelImpl(
|
||||
name: null == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
value: null == value
|
||||
? _value.value
|
||||
: value // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
type: null == type
|
||||
? _value.type
|
||||
: type // ignore: cast_nullable_to_non_nullable
|
||||
as FormDataType,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$FormDataModelImpl implements _FormDataModel {
|
||||
const _$FormDataModelImpl(
|
||||
{required this.name, required this.value, required this.type});
|
||||
|
||||
factory _$FormDataModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$FormDataModelImplFromJson(json);
|
||||
|
||||
@override
|
||||
final String name;
|
||||
@override
|
||||
final String value;
|
||||
@override
|
||||
final FormDataType type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'FormDataModel(name: $name, value: $value, type: $type)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FormDataModelImpl &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.value, value) || other.value == value) &&
|
||||
(identical(other.type, type) || other.type == type));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, name, value, type);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FormDataModelImplCopyWith<_$FormDataModelImpl> get copyWith =>
|
||||
__$$FormDataModelImplCopyWithImpl<_$FormDataModelImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$FormDataModelImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _FormDataModel implements FormDataModel {
|
||||
const factory _FormDataModel(
|
||||
{required final String name,
|
||||
required final String value,
|
||||
required final FormDataType type}) = _$FormDataModelImpl;
|
||||
|
||||
factory _FormDataModel.fromJson(Map<String, dynamic> json) =
|
||||
_$FormDataModelImpl.fromJson;
|
||||
|
||||
@override
|
||||
String get name;
|
||||
@override
|
||||
String get value;
|
||||
@override
|
||||
FormDataType get type;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$FormDataModelImplCopyWith<_$FormDataModelImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
26
lib/models/form_data_model.g.dart
Normal file
26
lib/models/form_data_model.g.dart
Normal file
@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'form_data_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$FormDataModelImpl _$$FormDataModelImplFromJson(Map<String, dynamic> json) =>
|
||||
_$FormDataModelImpl(
|
||||
name: json['name'] as String,
|
||||
value: json['value'] as String,
|
||||
type: $enumDecode(_$FormDataTypeEnumMap, json['type']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$FormDataModelImplToJson(_$FormDataModelImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'name': instance.name,
|
||||
'value': instance.value,
|
||||
'type': _$FormDataTypeEnumMap[instance.type]!,
|
||||
};
|
||||
|
||||
const _$FormDataTypeEnumMap = {
|
||||
FormDataType.text: 'text',
|
||||
FormDataType.file: 'file',
|
||||
};
|
@ -2,3 +2,4 @@ export 'name_value_model.dart';
|
||||
export 'request_model.dart';
|
||||
export 'response_model.dart';
|
||||
export 'settings_model.dart';
|
||||
export 'form_data_model.dart';
|
||||
|
@ -1,8 +1,14 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/utils/utils.dart' show mapToRows, rowsToMap;
|
||||
import 'name_value_model.dart';
|
||||
import 'response_model.dart';
|
||||
import '../utils/utils.dart'
|
||||
show
|
||||
mapListToFormDataModelRows,
|
||||
rowsToFormDataMapList,
|
||||
mapToRows,
|
||||
rowsToMap,
|
||||
getEnabledRows;
|
||||
import '../consts.dart';
|
||||
import 'models.dart';
|
||||
|
||||
@immutable
|
||||
class RequestModel {
|
||||
@ -15,8 +21,11 @@ class RequestModel {
|
||||
this.requestTabIndex = 0,
|
||||
this.requestHeaders,
|
||||
this.requestParams,
|
||||
this.isHeaderEnabledList,
|
||||
this.isParamEnabledList,
|
||||
this.requestBodyContentType = ContentType.json,
|
||||
this.requestBody,
|
||||
this.requestFormDataList,
|
||||
this.responseStatus,
|
||||
this.message,
|
||||
this.responseModel,
|
||||
@ -30,15 +39,34 @@ class RequestModel {
|
||||
final int requestTabIndex;
|
||||
final List<NameValueModel>? requestHeaders;
|
||||
final List<NameValueModel>? requestParams;
|
||||
final List<bool>? isHeaderEnabledList;
|
||||
final List<bool>? isParamEnabledList;
|
||||
final ContentType requestBodyContentType;
|
||||
final String? requestBody;
|
||||
final List<FormDataModel>? requestFormDataList;
|
||||
final int? responseStatus;
|
||||
final String? message;
|
||||
final ResponseModel? responseModel;
|
||||
|
||||
List<NameValueModel>? get enabledRequestHeaders =>
|
||||
getEnabledRows(requestHeaders, isHeaderEnabledList);
|
||||
List<NameValueModel>? get enabledRequestParams =>
|
||||
getEnabledRows(requestParams, isParamEnabledList);
|
||||
|
||||
Map<String, String> get enabledHeadersMap =>
|
||||
rowsToMap(enabledRequestHeaders) ?? {};
|
||||
Map<String, String> get enabledParamsMap =>
|
||||
rowsToMap(enabledRequestParams) ?? {};
|
||||
Map<String, String> get headersMap => rowsToMap(requestHeaders) ?? {};
|
||||
Map<String, String> get paramsMap => rowsToMap(requestParams) ?? {};
|
||||
|
||||
List<Map<String, dynamic>> get formDataMapList =>
|
||||
rowsToFormDataMapList(requestFormDataList) ?? [];
|
||||
bool get isFormDataRequest => requestBodyContentType == ContentType.formdata;
|
||||
|
||||
bool get hasContentTypeHeader => enabledHeadersMap.keys
|
||||
.any((k) => k.toLowerCase() == HttpHeaders.contentTypeHeader);
|
||||
|
||||
RequestModel duplicate({
|
||||
required String id,
|
||||
}) {
|
||||
@ -50,8 +78,14 @@ class RequestModel {
|
||||
description: description,
|
||||
requestHeaders: requestHeaders != null ? [...requestHeaders!] : null,
|
||||
requestParams: requestParams != null ? [...requestParams!] : null,
|
||||
isHeaderEnabledList:
|
||||
isHeaderEnabledList != null ? [...isHeaderEnabledList!] : null,
|
||||
isParamEnabledList:
|
||||
isParamEnabledList != null ? [...isParamEnabledList!] : null,
|
||||
requestBodyContentType: requestBodyContentType,
|
||||
requestBody: requestBody,
|
||||
requestFormDataList:
|
||||
requestFormDataList != null ? [...requestFormDataList!] : null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -64,14 +98,19 @@ class RequestModel {
|
||||
int? requestTabIndex,
|
||||
List<NameValueModel>? requestHeaders,
|
||||
List<NameValueModel>? requestParams,
|
||||
List<bool>? isHeaderEnabledList,
|
||||
List<bool>? isParamEnabledList,
|
||||
ContentType? requestBodyContentType,
|
||||
String? requestBody,
|
||||
List<FormDataModel>? requestFormDataList,
|
||||
int? responseStatus,
|
||||
String? message,
|
||||
ResponseModel? responseModel,
|
||||
}) {
|
||||
var headers = requestHeaders ?? this.requestHeaders;
|
||||
var params = requestParams ?? this.requestParams;
|
||||
var enabledHeaders = isHeaderEnabledList ?? this.isHeaderEnabledList;
|
||||
var enabledParams = isParamEnabledList ?? this.isParamEnabledList;
|
||||
return RequestModel(
|
||||
id: id ?? this.id,
|
||||
method: method ?? this.method,
|
||||
@ -81,9 +120,12 @@ class RequestModel {
|
||||
requestTabIndex: requestTabIndex ?? this.requestTabIndex,
|
||||
requestHeaders: headers != null ? [...headers] : null,
|
||||
requestParams: params != null ? [...params] : null,
|
||||
isHeaderEnabledList: enabledHeaders != null ? [...enabledHeaders] : null,
|
||||
isParamEnabledList: enabledParams != null ? [...enabledParams] : null,
|
||||
requestBodyContentType:
|
||||
requestBodyContentType ?? this.requestBodyContentType,
|
||||
requestBody: requestBody ?? this.requestBody,
|
||||
requestFormDataList: requestFormDataList ?? this.requestFormDataList,
|
||||
responseStatus: responseStatus ?? this.responseStatus,
|
||||
message: message ?? this.message,
|
||||
responseModel: responseModel ?? this.responseModel,
|
||||
@ -106,6 +148,8 @@ class RequestModel {
|
||||
final description = data["description"] as String?;
|
||||
final requestHeaders = data["requestHeaders"];
|
||||
final requestParams = data["requestParams"];
|
||||
final isHeaderEnabledList = data["isHeaderEnabledList"] as List<bool>?;
|
||||
final isParamEnabledList = data["isParamEnabledList"] as List<bool>?;
|
||||
try {
|
||||
requestBodyContentType =
|
||||
ContentType.values.byName(data["requestBodyContentType"] as String);
|
||||
@ -113,9 +157,11 @@ class RequestModel {
|
||||
requestBodyContentType = kDefaultContentType;
|
||||
}
|
||||
final requestBody = data["requestBody"] as String?;
|
||||
final requestFormDataList = data["requestFormDataList"];
|
||||
final responseStatus = data["responseStatus"] as int?;
|
||||
final message = data["message"] as String?;
|
||||
final responseModelJson = data["responseModel"];
|
||||
|
||||
if (responseModelJson != null) {
|
||||
responseModel =
|
||||
ResponseModel.fromJson(Map<String, dynamic>.from(responseModelJson));
|
||||
@ -136,8 +182,13 @@ class RequestModel {
|
||||
requestParams: requestParams != null
|
||||
? mapToRows(Map<String, String>.from(requestParams))
|
||||
: null,
|
||||
isHeaderEnabledList: isHeaderEnabledList,
|
||||
isParamEnabledList: isParamEnabledList,
|
||||
requestBodyContentType: requestBodyContentType,
|
||||
requestBody: requestBody,
|
||||
requestFormDataList: requestFormDataList != null
|
||||
? mapListToFormDataModelRows(List<Map>.from(requestFormDataList))
|
||||
: null,
|
||||
responseStatus: responseStatus,
|
||||
message: message,
|
||||
responseModel: responseModel,
|
||||
@ -153,8 +204,11 @@ class RequestModel {
|
||||
"description": description,
|
||||
"requestHeaders": rowsToMap(requestHeaders),
|
||||
"requestParams": rowsToMap(requestParams),
|
||||
"isHeaderEnabledList": isHeaderEnabledList,
|
||||
"isParamEnabledList": isParamEnabledList,
|
||||
"requestBodyContentType": requestBodyContentType.name,
|
||||
"requestBody": requestBody,
|
||||
"requestFormDataList": rowsToFormDataMapList(requestFormDataList),
|
||||
"responseStatus": includeResponse ? responseStatus : null,
|
||||
"message": includeResponse ? message : null,
|
||||
"responseModel": includeResponse ? responseModel?.toJson() : null,
|
||||
@ -171,9 +225,12 @@ class RequestModel {
|
||||
"Request Description: $description",
|
||||
"Request Tab Index: ${requestTabIndex.toString()}",
|
||||
"Request Headers: ${requestHeaders.toString()}",
|
||||
"Enabled Headers: ${isHeaderEnabledList.toString()}",
|
||||
"Request Params: ${requestParams.toString()}",
|
||||
"Enabled Params: ${isParamEnabledList.toString()}",
|
||||
"Request Body Content Type: ${requestBodyContentType.toString()}",
|
||||
"Request Body: ${requestBody.toString()}",
|
||||
"Request FormData: ${requestFormDataList.toString()}",
|
||||
"Response Status: $responseStatus",
|
||||
"Response Message: $message",
|
||||
"Response: ${responseModel.toString()}"
|
||||
@ -192,8 +249,11 @@ class RequestModel {
|
||||
other.requestTabIndex == requestTabIndex &&
|
||||
listEquals(other.requestHeaders, requestHeaders) &&
|
||||
listEquals(other.requestParams, requestParams) &&
|
||||
listEquals(other.isHeaderEnabledList, isHeaderEnabledList) &&
|
||||
listEquals(other.isParamEnabledList, isParamEnabledList) &&
|
||||
other.requestBodyContentType == requestBodyContentType &&
|
||||
other.requestBody == requestBody &&
|
||||
other.requestFormDataList == requestFormDataList &&
|
||||
other.responseStatus == responseStatus &&
|
||||
other.message == message &&
|
||||
other.responseModel == responseModel;
|
||||
@ -211,8 +271,11 @@ class RequestModel {
|
||||
requestTabIndex,
|
||||
requestHeaders,
|
||||
requestParams,
|
||||
isHeaderEnabledList,
|
||||
isParamEnabledList,
|
||||
requestBodyContentType,
|
||||
requestBody,
|
||||
requestFormDataList,
|
||||
responseStatus,
|
||||
message,
|
||||
responseModel,
|
||||
|
@ -101,4 +101,32 @@ class SettingsModel {
|
||||
String toString() {
|
||||
return toJson().toString();
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is SettingsModel &&
|
||||
other.runtimeType == runtimeType &&
|
||||
other.isDark == isDark &&
|
||||
other.alwaysShowCollectionPaneScrollbar ==
|
||||
alwaysShowCollectionPaneScrollbar &&
|
||||
other.size == size &&
|
||||
other.offset == offset &&
|
||||
other.defaultUriScheme == defaultUriScheme &&
|
||||
other.defaultCodeGenLang == defaultCodeGenLang &&
|
||||
other.saveResponses == saveResponses;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return Object.hash(
|
||||
runtimeType,
|
||||
isDark,
|
||||
alwaysShowCollectionPaneScrollbar,
|
||||
size,
|
||||
offset,
|
||||
defaultUriScheme,
|
||||
defaultCodeGenLang,
|
||||
saveResponses,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import '../models/models.dart';
|
||||
import '../services/services.dart' show hiveHandler, HiveHandler, request;
|
||||
import '../utils/utils.dart' show uuid, collectionToHAR;
|
||||
import '../consts.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
final activeIdStateProvider = StateProvider<String?>((ref) => null);
|
||||
|
||||
@ -123,8 +124,11 @@ class CollectionStateNotifier
|
||||
int? requestTabIndex,
|
||||
List<NameValueModel>? requestHeaders,
|
||||
List<NameValueModel>? requestParams,
|
||||
List<bool>? isHeaderEnabledList,
|
||||
List<bool>? isParamEnabledList,
|
||||
ContentType? requestBodyContentType,
|
||||
String? requestBody,
|
||||
List<FormDataModel>? requestFormDataList,
|
||||
int? responseStatus,
|
||||
String? message,
|
||||
ResponseModel? responseModel,
|
||||
@ -137,8 +141,11 @@ class CollectionStateNotifier
|
||||
requestTabIndex: requestTabIndex,
|
||||
requestHeaders: requestHeaders,
|
||||
requestParams: requestParams,
|
||||
isHeaderEnabledList: isHeaderEnabledList,
|
||||
isParamEnabledList: isParamEnabledList,
|
||||
requestBodyContentType: requestBodyContentType,
|
||||
requestBody: requestBody,
|
||||
requestFormDataList: requestFormDataList,
|
||||
responseStatus: responseStatus,
|
||||
message: message,
|
||||
responseModel: responseModel);
|
||||
@ -153,10 +160,13 @@ class CollectionStateNotifier
|
||||
ref.read(codePaneVisibleStateProvider.notifier).state = false;
|
||||
final defaultUriScheme =
|
||||
ref.read(settingsProvider.select((value) => value.defaultUriScheme));
|
||||
|
||||
RequestModel requestModel = state![id]!;
|
||||
var responseRec =
|
||||
await request(requestModel, defaultUriScheme: defaultUriScheme);
|
||||
(http.Response?, Duration?, String?)? responseRec = await request(
|
||||
requestModel,
|
||||
defaultUriScheme: defaultUriScheme,
|
||||
isMultiPartRequest:
|
||||
requestModel.requestBodyContentType == ContentType.formdata,
|
||||
);
|
||||
late final RequestModel newRequestModel;
|
||||
if (responseRec.$1 == null) {
|
||||
newRequestModel = requestModel.copyWith(
|
||||
@ -175,7 +185,6 @@ class CollectionStateNotifier
|
||||
responseModel: responseModel,
|
||||
);
|
||||
}
|
||||
//print(newRequestModel);
|
||||
ref.read(sentRequestIdStateProvider.notifier).state = null;
|
||||
var map = {...state!};
|
||||
map[id] = newRequestModel;
|
||||
|
@ -6,16 +6,11 @@ import 'home_page/home_page.dart';
|
||||
import 'intro_page.dart';
|
||||
import 'settings_page.dart';
|
||||
|
||||
class Dashboard extends ConsumerStatefulWidget {
|
||||
class Dashboard extends ConsumerWidget {
|
||||
const Dashboard({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<Dashboard> createState() => _DashboardState();
|
||||
}
|
||||
|
||||
class _DashboardState extends ConsumerState<Dashboard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final railIdx = ref.watch(navRailIndexStateProvider);
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
@ -50,13 +45,13 @@ class _DashboardState extends ConsumerState<Dashboard> {
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16.0),
|
||||
child: bottomButton(context, railIdx, 1, Icons.help,
|
||||
Icons.help_outline),
|
||||
child: bottomButton(context, ref, railIdx, 1,
|
||||
Icons.help, Icons.help_outline),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16.0),
|
||||
child: bottomButton(context, railIdx, 2, Icons.settings,
|
||||
Icons.settings_outlined),
|
||||
child: bottomButton(context, ref, railIdx, 2,
|
||||
Icons.settings, Icons.settings_outlined),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -99,6 +94,7 @@ class _DashboardState extends ConsumerState<Dashboard> {
|
||||
|
||||
TextButton bottomButton(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
int railIdx,
|
||||
int buttonIdx,
|
||||
IconData selectedIcon,
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'request_form_data.dart';
|
||||
|
||||
class EditRequestBody extends ConsumerStatefulWidget {
|
||||
const EditRequestBody({super.key});
|
||||
@ -18,6 +19,10 @@ class _EditRequestBodyState extends ConsumerState<EditRequestBody> {
|
||||
final requestModel = ref
|
||||
.read(collectionStateNotifierProvider.notifier)
|
||||
.getRequestModel(activeId!);
|
||||
ContentType? requestBodyStateWatcher = (ref
|
||||
.watch(collectionStateNotifierProvider)![activeId]
|
||||
?.requestBodyContentType) ??
|
||||
ContentType.values.first;
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
@ -38,7 +43,9 @@ class _EditRequestBodyState extends ConsumerState<EditRequestBody> {
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextFieldEditor(
|
||||
child: requestBodyStateWatcher == ContentType.formdata
|
||||
? const FormDataWidget()
|
||||
: TextFieldEditor(
|
||||
key: Key("$activeId-body"),
|
||||
fieldKey: "$activeId-body-editor",
|
||||
initialValue: requestModel?.requestBody,
|
||||
|
@ -0,0 +1,223 @@
|
||||
import 'dart:math';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/models/form_data_model.dart';
|
||||
import 'package:apidash/models/models.dart';
|
||||
import 'package:apidash/providers/collection_providers.dart';
|
||||
import 'package:apidash/widgets/form_data_field.dart';
|
||||
import 'package:apidash/widgets/textfields.dart';
|
||||
import 'package:davi/davi.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
class FormDataWidget extends ConsumerStatefulWidget {
|
||||
const FormDataWidget({super.key});
|
||||
@override
|
||||
ConsumerState<FormDataWidget> createState() => _FormDataBodyState();
|
||||
}
|
||||
|
||||
class _FormDataBodyState extends ConsumerState<FormDataWidget> {
|
||||
late int seed;
|
||||
final random = Random.secure();
|
||||
late List<FormDataModel> rows;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
seed = random.nextInt(kRandMax);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final activeId = ref.watch(activeIdStateProvider);
|
||||
var formRows = ref.read(activeRequestModelProvider)?.requestFormDataList;
|
||||
rows =
|
||||
formRows == null || formRows.isEmpty ? [kFormDataEmptyModel] : formRows;
|
||||
|
||||
DaviModel<FormDataModel> daviModelRows = DaviModel<FormDataModel>(
|
||||
rows: rows,
|
||||
columns: [
|
||||
DaviColumn(
|
||||
cellPadding: kpsV5,
|
||||
name: 'Key',
|
||||
grow: 4,
|
||||
cellBuilder: (_, row) {
|
||||
int idx = row.index;
|
||||
return Theme(
|
||||
data: Theme.of(context),
|
||||
child: FormDataField(
|
||||
keyId: "$activeId-$idx-form-v-$seed",
|
||||
initialValue: rows[idx].name,
|
||||
hintText: " Add Key",
|
||||
onChanged: (value) {
|
||||
rows[idx] = rows[idx].copyWith(
|
||||
name: value,
|
||||
);
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
formDataType: rows[idx].type,
|
||||
onFormDataTypeChanged: (value) {
|
||||
rows[idx] = rows[idx].copyWith(
|
||||
type: value ?? FormDataType.text,
|
||||
);
|
||||
rows[idx] = rows[idx].copyWith(value: "");
|
||||
setState(() {});
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
sortable: false,
|
||||
),
|
||||
DaviColumn(
|
||||
width: 40,
|
||||
cellPadding: kpsV5,
|
||||
cellAlignment: Alignment.center,
|
||||
cellBuilder: (_, row) {
|
||||
return Text(
|
||||
"=",
|
||||
style: kCodeStyle,
|
||||
);
|
||||
},
|
||||
),
|
||||
DaviColumn(
|
||||
name: 'Value',
|
||||
grow: 4,
|
||||
cellPadding: kpsV5,
|
||||
cellBuilder: (_, row) {
|
||||
int idx = row.index;
|
||||
return rows[idx].type == FormDataType.file
|
||||
? Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Theme(
|
||||
data: Theme.of(context),
|
||||
child: ElevatedButton.icon(
|
||||
icon: const Icon(
|
||||
Icons.snippet_folder_rounded,
|
||||
size: 20,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStatePropertyAll(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
FilePickerResult? pickedResult =
|
||||
await FilePicker.platform.pickFiles();
|
||||
if (pickedResult != null &&
|
||||
pickedResult.files.isNotEmpty &&
|
||||
pickedResult.files.first.path != null) {
|
||||
rows[idx] = rows[idx].copyWith(
|
||||
value: pickedResult.files.first.path!,
|
||||
);
|
||||
setState(() {});
|
||||
_onFieldChange(activeId!);
|
||||
}
|
||||
},
|
||||
label: Text(
|
||||
(rows[idx].type == FormDataType.file &&
|
||||
rows[idx].value.isNotEmpty)
|
||||
? rows[idx].value.toString()
|
||||
: "Select File",
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: kFormDataButtonLabelTextStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: CellField(
|
||||
keyId: "$activeId-$idx-form-v-$seed",
|
||||
initialValue: rows[idx].value,
|
||||
hintText: " Add Value",
|
||||
onChanged: (value) {
|
||||
rows[idx] = rows[idx].copyWith(value: value);
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
);
|
||||
},
|
||||
sortable: false,
|
||||
),
|
||||
DaviColumn(
|
||||
pinStatus: PinStatus.none,
|
||||
width: 30,
|
||||
cellBuilder: (_, row) {
|
||||
return InkWell(
|
||||
child: Theme.of(context).brightness == Brightness.dark
|
||||
? kIconRemoveDark
|
||||
: kIconRemoveLight,
|
||||
onTap: () {
|
||||
seed = random.nextInt(kRandMax);
|
||||
if (rows.length == 1) {
|
||||
setState(() {
|
||||
rows = [kFormDataEmptyModel];
|
||||
});
|
||||
} else {
|
||||
rows.removeAt(row.index);
|
||||
}
|
||||
_onFieldChange(activeId!);
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
borderRadius: kBorderRadius12,
|
||||
),
|
||||
margin: kP10,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DaviTheme(
|
||||
data: kTableThemeData,
|
||||
child: Davi<FormDataModel>(daviModelRows),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 30),
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
rows.add(kFormDataEmptyModel);
|
||||
});
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
label: const Text(
|
||||
"Add Form Data",
|
||||
style: kTextStyleButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _onFieldChange(String activeId) {
|
||||
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||
activeId,
|
||||
requestFormDataList: rows,
|
||||
);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ class EditRequestHeaders extends ConsumerStatefulWidget {
|
||||
|
||||
class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
||||
late List<NameValueModel> rows;
|
||||
late List<bool> isRowEnabledList;
|
||||
final random = Random.secure();
|
||||
late int seed;
|
||||
|
||||
@ -26,9 +27,11 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
||||
}
|
||||
|
||||
void _onFieldChange(String activeId) {
|
||||
ref
|
||||
.read(collectionStateNotifierProvider.notifier)
|
||||
.update(activeId, requestHeaders: rows);
|
||||
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||
activeId,
|
||||
requestHeaders: rows,
|
||||
isHeaderEnabledList: isRowEnabledList,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -42,12 +45,34 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
||||
kNameValueEmptyModel,
|
||||
]
|
||||
: rH;
|
||||
isRowEnabledList =
|
||||
ref.read(activeRequestModelProvider)?.isHeaderEnabledList ??
|
||||
List.filled(rows.length, true, growable: true);
|
||||
|
||||
DaviModel<NameValueModel> model = DaviModel<NameValueModel>(
|
||||
rows: rows,
|
||||
columns: [
|
||||
DaviColumn(
|
||||
name: 'Checkbox',
|
||||
width: 30,
|
||||
cellBuilder: (_, row) {
|
||||
int idx = row.index;
|
||||
return CheckBox(
|
||||
keyId: "$activeId-$idx-headers-c-$seed",
|
||||
value: isRowEnabledList[idx],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
isRowEnabledList[idx] = value!;
|
||||
});
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
);
|
||||
},
|
||||
),
|
||||
DaviColumn(
|
||||
name: 'Header Name',
|
||||
width: 70,
|
||||
grow: 1,
|
||||
cellBuilder: (_, row) {
|
||||
int idx = row.index;
|
||||
@ -106,9 +131,11 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
||||
rows = [
|
||||
kNameValueEmptyModel,
|
||||
];
|
||||
isRowEnabledList = [true];
|
||||
});
|
||||
} else {
|
||||
rows.removeAt(row.index);
|
||||
isRowEnabledList.removeAt(row.index);
|
||||
}
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
@ -143,6 +170,7 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
rows.add(kNameValueEmptyModel);
|
||||
isRowEnabledList.add(true);
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
|
@ -17,6 +17,7 @@ class EditRequestURLParams extends ConsumerStatefulWidget {
|
||||
|
||||
class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
||||
late List<NameValueModel> rows;
|
||||
late List<bool> isRowEnabledList;
|
||||
final random = Random.secure();
|
||||
late int seed;
|
||||
|
||||
@ -27,9 +28,11 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
||||
}
|
||||
|
||||
void _onFieldChange(String activeId) {
|
||||
ref
|
||||
.read(collectionStateNotifierProvider.notifier)
|
||||
.update(activeId, requestParams: rows);
|
||||
ref.read(collectionStateNotifierProvider.notifier).update(
|
||||
activeId,
|
||||
requestParams: rows,
|
||||
isParamEnabledList: isRowEnabledList,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -43,12 +46,35 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
||||
kNameValueEmptyModel,
|
||||
]
|
||||
: rP;
|
||||
isRowEnabledList =
|
||||
ref.read(activeRequestModelProvider)?.isParamEnabledList ??
|
||||
List.filled(rows.length, true, growable: true);
|
||||
|
||||
DaviModel<NameValueModel> model = DaviModel<NameValueModel>(
|
||||
rows: rows,
|
||||
columns: [
|
||||
DaviColumn(
|
||||
name: 'Checkbox',
|
||||
width: 30,
|
||||
cellBuilder: (_, row) {
|
||||
int idx = row.index;
|
||||
|
||||
return CheckBox(
|
||||
keyId: "$activeId-$idx-params-c-$seed",
|
||||
value: isRowEnabledList[idx],
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
isRowEnabledList[idx] = value!;
|
||||
});
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
colorScheme: Theme.of(context).colorScheme,
|
||||
);
|
||||
},
|
||||
),
|
||||
DaviColumn(
|
||||
name: 'URL Parameter',
|
||||
width: 70,
|
||||
grow: 1,
|
||||
cellBuilder: (_, row) {
|
||||
int idx = row.index;
|
||||
@ -107,9 +133,11 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
||||
rows = [
|
||||
kNameValueEmptyModel,
|
||||
];
|
||||
isRowEnabledList = [true];
|
||||
});
|
||||
} else {
|
||||
rows.removeAt(row.index);
|
||||
isRowEnabledList.removeAt(row.index);
|
||||
}
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
@ -144,6 +172,7 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
rows.add(kNameValueEmptyModel);
|
||||
isRowEnabledList.add(true);
|
||||
_onFieldChange(activeId!);
|
||||
},
|
||||
icon: const Icon(Icons.add),
|
||||
|
@ -27,7 +27,7 @@ class _RequestEditorPaneState extends ConsumerState<RequestEditorPane> {
|
||||
return const RequestEditorDefault();
|
||||
} else {
|
||||
return Padding(
|
||||
padding: kIsMacOS ? kPt24o8 : kP8,
|
||||
padding: kIsMacOS || kIsWindows ? kPt24o8 : kP8,
|
||||
child: const Column(
|
||||
children: [
|
||||
EditorPaneRequestURLCard(),
|
||||
|
@ -4,20 +4,9 @@ import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class EditorPaneRequestURLCard extends StatefulWidget {
|
||||
class EditorPaneRequestURLCard extends StatelessWidget {
|
||||
const EditorPaneRequestURLCard({super.key});
|
||||
|
||||
@override
|
||||
State<EditorPaneRequestURLCard> createState() =>
|
||||
_EditorPaneRequestURLCardState();
|
||||
}
|
||||
|
||||
class _EditorPaneRequestURLCardState extends State<EditorPaneRequestURLCard> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
@ -52,25 +41,13 @@ class _EditorPaneRequestURLCardState extends State<EditorPaneRequestURLCard> {
|
||||
}
|
||||
}
|
||||
|
||||
class DropdownButtonHTTPMethod extends ConsumerStatefulWidget {
|
||||
class DropdownButtonHTTPMethod extends ConsumerWidget {
|
||||
const DropdownButtonHTTPMethod({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<DropdownButtonHTTPMethod> createState() =>
|
||||
_DropdownButtonHTTPMethodState();
|
||||
}
|
||||
|
||||
class _DropdownButtonHTTPMethodState
|
||||
extends ConsumerState<DropdownButtonHTTPMethod> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final method =
|
||||
ref.watch(activeRequestModelProvider.select((value) => value?.method));
|
||||
return DropdownButtonHttpMethod(
|
||||
@ -85,23 +62,13 @@ class _DropdownButtonHTTPMethodState
|
||||
}
|
||||
}
|
||||
|
||||
class URLTextField extends ConsumerStatefulWidget {
|
||||
class URLTextField extends ConsumerWidget {
|
||||
const URLTextField({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<URLTextField> createState() => _URLTextFieldState();
|
||||
}
|
||||
|
||||
class _URLTextFieldState extends ConsumerState<URLTextField> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final activeId = ref.watch(activeIdStateProvider);
|
||||
return URLField(
|
||||
activeId: activeId!,
|
||||
@ -118,23 +85,13 @@ class _URLTextFieldState extends ConsumerState<URLTextField> {
|
||||
}
|
||||
}
|
||||
|
||||
class SendButton extends ConsumerStatefulWidget {
|
||||
class SendButton extends ConsumerWidget {
|
||||
const SendButton({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
ConsumerState<SendButton> createState() => _SendButtonState();
|
||||
}
|
||||
|
||||
class _SendButtonState extends ConsumerState<SendButton> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final activeId = ref.watch(activeIdStateProvider);
|
||||
final sentRequestId = ref.watch(sentRequestIdStateProvider);
|
||||
return SendRequestButton(
|
||||
|
@ -3,14 +3,9 @@ import 'package:apidash/widgets/widgets.dart';
|
||||
import 'editor_pane/editor_pane.dart';
|
||||
import 'collection_pane.dart';
|
||||
|
||||
class HomePage extends StatefulWidget {
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
HomePageState createState() => HomePageState();
|
||||
}
|
||||
|
||||
class HomePageState extends State<HomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Column(
|
||||
|
@ -1,14 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
|
||||
class IntroPage extends StatefulWidget {
|
||||
class IntroPage extends StatelessWidget {
|
||||
const IntroPage({super.key});
|
||||
|
||||
@override
|
||||
State<IntroPage> createState() => _IntroPageState();
|
||||
}
|
||||
|
||||
class _IntroPageState extends State<IntroPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const IntroMessage();
|
||||
|
83
lib/screens/mobile/dashboard.dart
Normal file
83
lib/screens/mobile/dashboard.dart
Normal file
@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../intro_page.dart';
|
||||
import '../settings_page.dart';
|
||||
import '../home_page/collection_pane.dart';
|
||||
|
||||
class MobileDashboard extends ConsumerStatefulWidget {
|
||||
const MobileDashboard(
|
||||
{required this.scaffoldBody, required this.title, super.key});
|
||||
|
||||
final Widget scaffoldBody;
|
||||
final String title;
|
||||
|
||||
@override
|
||||
ConsumerState<MobileDashboard> createState() => _MobileDashboardState();
|
||||
}
|
||||
|
||||
class _MobileDashboardState extends ConsumerState<MobileDashboard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
),
|
||||
drawer: Drawer(
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 70,
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Home'),
|
||||
leading: const Icon(Icons.home_outlined),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const MobileDashboard(
|
||||
title: 'Home',
|
||||
scaffoldBody: IntroPage(),
|
||||
),
|
||||
),
|
||||
(Route<dynamic> route) => false);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Requests'),
|
||||
leading: const Icon(Icons.auto_awesome_mosaic_outlined),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const MobileDashboard(
|
||||
title: 'Requests',
|
||||
scaffoldBody: CollectionPane(),
|
||||
),
|
||||
),
|
||||
(Route<dynamic> route) => false);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Settings'),
|
||||
leading: const Icon(Icons.settings_outlined),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const MobileDashboard(
|
||||
title: 'Settings',
|
||||
scaffoldBody: SettingsPage(),
|
||||
),
|
||||
),
|
||||
(Route<dynamic> route) => false);
|
||||
},
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: SafeArea(
|
||||
child: widget.scaffoldBody,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
1
lib/screens/mobile/mobile.dart
Normal file
1
lib/screens/mobile/mobile.dart
Normal file
@ -0,0 +1 @@
|
||||
export 'dashboard.dart';
|
@ -1 +1,3 @@
|
||||
export "dashboard.dart";
|
||||
export 'dashboard.dart';
|
||||
export 'mobile/mobile.dart';
|
||||
export 'home_page/collection_pane.dart';
|
||||
|
@ -2,34 +2,40 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../providers/providers.dart';
|
||||
import '../widgets/widgets.dart';
|
||||
import '../utils/utils.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import '../common/utils.dart';
|
||||
import '../consts.dart';
|
||||
|
||||
class SettingsPage extends ConsumerStatefulWidget {
|
||||
class SettingsPage extends ConsumerWidget {
|
||||
const SettingsPage({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<SettingsPage> createState() => _SettingsPageState();
|
||||
}
|
||||
|
||||
class _SettingsPageState extends ConsumerState<SettingsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final settings = ref.watch(settingsProvider);
|
||||
final clearingData = ref.watch(clearDataStateProvider);
|
||||
var sm = ScaffoldMessenger.of(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
constraints: const BoxConstraints(maxWidth: 800),
|
||||
child: ListView(
|
||||
Padding(
|
||||
padding: kPh20t40,
|
||||
child: kIsDesktop
|
||||
? Text("Settings",
|
||||
style: Theme.of(context).textTheme.headlineLarge)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
kIsDesktop
|
||||
? const Padding(
|
||||
padding: kPh20,
|
||||
child: Divider(
|
||||
height: 1,
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
padding: kPh20,
|
||||
children: [
|
||||
Text("Settings",
|
||||
style: Theme.of(context).textTheme.headlineLarge),
|
||||
const Divider(),
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
hoverColor: kColorTransparent,
|
||||
@ -112,26 +118,18 @@ class _SettingsPageState extends ConsumerState<SettingsPage> {
|
||||
title: const Text('Export Data'),
|
||||
subtitle: const Text(
|
||||
'Export your collection to HAR (HTTP Archive format).\nVersion control this file or import in other API clients.'),
|
||||
trailing: FilledButton(
|
||||
trailing: FilledButton.icon(
|
||||
onPressed: () async {
|
||||
var message = "";
|
||||
try {
|
||||
var data = await ref
|
||||
.read(collectionStateNotifierProvider.notifier)
|
||||
.exportDataToHAR();
|
||||
var pth = await getFileDownloadpath(null, "har");
|
||||
if (pth != null) {
|
||||
await saveFile(pth, jsonMapToBytes(data));
|
||||
var sp = getShortPath(pth);
|
||||
message = 'Saved to $sp';
|
||||
}
|
||||
} catch (e) {
|
||||
message = "An error occurred while exporting.";
|
||||
}
|
||||
sm.hideCurrentSnackBar();
|
||||
sm.showSnackBar(getSnackBar(message, small: false));
|
||||
await saveCollection(data, sm);
|
||||
},
|
||||
child: const Text("Export Data"),
|
||||
label: const Text("Export"),
|
||||
icon: const Icon(
|
||||
Icons.arrow_outward_rounded,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
@ -139,7 +137,7 @@ class _SettingsPageState extends ConsumerState<SettingsPage> {
|
||||
hoverColor: kColorTransparent,
|
||||
title: const Text('Clear Data'),
|
||||
subtitle: const Text('Delete all requests data from the disk'),
|
||||
trailing: FilledButton.tonal(
|
||||
trailing: FilledButton.tonalIcon(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: settings.isDark
|
||||
? kColorDarkDanger
|
||||
@ -183,7 +181,11 @@ class _SettingsPageState extends ConsumerState<SettingsPage> {
|
||||
],
|
||||
),
|
||||
),
|
||||
child: const Text("Clear Data"),
|
||||
label: const Text("Clear"),
|
||||
icon: const Icon(
|
||||
Icons.delete_forever_rounded,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
const String kDataBox = "data";
|
||||
const String kDataBox = "apidash-data";
|
||||
const String kKeyDataBoxIds = "ids";
|
||||
|
||||
const String kSettingsBox = "settings";
|
||||
const String kSettingsBox = "apidash-settings";
|
||||
|
||||
Future<void> openBoxes() async {
|
||||
await Hive.initFlutter();
|
||||
|
@ -9,15 +9,16 @@ import 'package:apidash/consts.dart';
|
||||
Future<(http.Response?, Duration?, String?)> request(
|
||||
RequestModel requestModel, {
|
||||
String defaultUriScheme = kDefaultUriScheme,
|
||||
bool isMultiPartRequest = false,
|
||||
}) async {
|
||||
(Uri?, String?) uriRec = getValidRequestUri(
|
||||
requestModel.url,
|
||||
requestModel.requestParams,
|
||||
requestModel.enabledRequestParams,
|
||||
defaultUriScheme: defaultUriScheme,
|
||||
);
|
||||
if (uriRec.$1 != null) {
|
||||
Uri requestUrl = uriRec.$1!;
|
||||
Map<String, String> headers = requestModel.headersMap;
|
||||
Map<String, String> headers = requestModel.enabledHeadersMap;
|
||||
http.Response response;
|
||||
String? body;
|
||||
try {
|
||||
@ -28,11 +29,38 @@ Future<(http.Response?, Duration?, String?)> request(
|
||||
if (contentLength > 0) {
|
||||
body = requestBody;
|
||||
headers[HttpHeaders.contentLengthHeader] = contentLength.toString();
|
||||
if (!requestModel.hasContentTypeHeader) {
|
||||
headers[HttpHeaders.contentTypeHeader] =
|
||||
kContentTypeMap[requestModel.requestBodyContentType] ?? "";
|
||||
requestModel.requestBodyContentType.header;
|
||||
}
|
||||
}
|
||||
}
|
||||
Stopwatch stopwatch = Stopwatch()..start();
|
||||
if (isMultiPartRequest) {
|
||||
var multiPartRequest = http.MultipartRequest(
|
||||
requestModel.method.name.toUpperCase(),
|
||||
requestUrl,
|
||||
);
|
||||
multiPartRequest.headers.addAll(headers);
|
||||
for (FormDataModel formData
|
||||
in (requestModel.requestFormDataList ?? [])) {
|
||||
if (formData.type == FormDataType.text) {
|
||||
multiPartRequest.fields.addAll({formData.name: formData.value});
|
||||
} else {
|
||||
multiPartRequest.files.add(
|
||||
await http.MultipartFile.fromPath(
|
||||
formData.name,
|
||||
formData.value,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
http.StreamedResponse multiPartResponse = await multiPartRequest.send();
|
||||
stopwatch.stop();
|
||||
http.Response convertedMultiPartResponse =
|
||||
await convertStreamedResponse(multiPartResponse);
|
||||
return (convertedMultiPartResponse, stopwatch.elapsed, null);
|
||||
}
|
||||
switch (requestModel.method) {
|
||||
case HTTPVerb.get:
|
||||
response = await http.get(requestUrl, headers: headers);
|
||||
|
@ -62,7 +62,7 @@ Future<void> setupWindow({Size? sz, Offset? off, bool center = false}) async {
|
||||
minimumSize: kMinWindowSize,
|
||||
skipTaskbar: false,
|
||||
title: kWindowTitle,
|
||||
titleBarStyle: kIsMacOS ? TitleBarStyle.hidden : null,
|
||||
titleBarStyle: kIsMacOS || kIsWindows ? TitleBarStyle.hidden : null,
|
||||
);
|
||||
if (off != null) {
|
||||
await windowManager.setPosition(off);
|
||||
|
@ -2,6 +2,7 @@ import 'dart:typed_data';
|
||||
import 'dart:convert';
|
||||
import '../models/models.dart';
|
||||
import '../consts.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
String humanizeDuration(Duration? duration) {
|
||||
if (duration == null) {
|
||||
@ -89,6 +90,43 @@ List<NameValueModel>? mapToRows(Map<String, String>? kvMap) {
|
||||
return finalRows;
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>>? rowsToFormDataMapList(
|
||||
List<FormDataModel>? kvRows,
|
||||
) {
|
||||
if (kvRows == null) {
|
||||
return null;
|
||||
}
|
||||
List<Map<String, dynamic>> finalMap = kvRows
|
||||
.map((FormDataModel formData) => {
|
||||
"name": formData.name,
|
||||
"value": formData.value,
|
||||
"type": formData.type.name,
|
||||
})
|
||||
.toList();
|
||||
return finalMap;
|
||||
}
|
||||
|
||||
List<FormDataModel>? mapListToFormDataModelRows(List<Map>? kvMap) {
|
||||
if (kvMap == null) {
|
||||
return null;
|
||||
}
|
||||
List<FormDataModel> finalRows = kvMap.map(
|
||||
(formData) {
|
||||
return FormDataModel(
|
||||
name: formData["name"],
|
||||
value: formData["value"],
|
||||
type: getFormDataType(formData["type"]),
|
||||
);
|
||||
},
|
||||
).toList();
|
||||
return finalRows;
|
||||
}
|
||||
|
||||
FormDataType getFormDataType(String? type) {
|
||||
return FormDataType.values.firstWhere((element) => element.name == type,
|
||||
orElse: () => FormDataType.text);
|
||||
}
|
||||
|
||||
Uint8List? stringToBytes(String? text) {
|
||||
if (text == null) {
|
||||
return null;
|
||||
@ -109,3 +147,30 @@ Uint8List jsonMapToBytes(Map<String, dynamic>? map) {
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
Future<http.Response> convertStreamedResponse(
|
||||
http.StreamedResponse streamedResponse,
|
||||
) async {
|
||||
Uint8List bodyBytes = await streamedResponse.stream.toBytes();
|
||||
|
||||
http.Response response = http.Response.bytes(
|
||||
bodyBytes,
|
||||
streamedResponse.statusCode,
|
||||
headers: streamedResponse.headers,
|
||||
persistentConnection: streamedResponse.persistentConnection,
|
||||
reasonPhrase: streamedResponse.reasonPhrase,
|
||||
request: streamedResponse.request,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
List<NameValueModel>? getEnabledRows(
|
||||
List<NameValueModel>? rows, List<bool>? isRowEnabledList) {
|
||||
if (rows == null || isRowEnabledList == null) {
|
||||
return rows;
|
||||
}
|
||||
List<NameValueModel> finalRows =
|
||||
rows.where((element) => isRowEnabledList[rows.indexOf(element)]).toList();
|
||||
return finalRows == [] ? null : finalRows;
|
||||
}
|
||||
|
@ -7,6 +7,10 @@ import 'package:path_provider/path_provider.dart';
|
||||
|
||||
const uuid = Uuid();
|
||||
|
||||
String getNewUuid() {
|
||||
return uuid.v1();
|
||||
}
|
||||
|
||||
String? getFileExtension(String? mimeType) {
|
||||
if (mimeType == null) {
|
||||
return null;
|
||||
|
@ -74,13 +74,14 @@ Map<String, dynamic> requestModelToHARJsonRequest(
|
||||
RequestModel requestModel, {
|
||||
defaultUriScheme = kDefaultUriScheme,
|
||||
bool exportMode = false,
|
||||
bool useEnabled = false,
|
||||
}) {
|
||||
Map<String, dynamic> json = {};
|
||||
bool hasBody = false;
|
||||
|
||||
var rec = getValidRequestUri(
|
||||
requestModel.url,
|
||||
requestModel.requestParams,
|
||||
useEnabled ? requestModel.enabledRequestParams : requestModel.requestParams,
|
||||
defaultUriScheme: defaultUriScheme,
|
||||
);
|
||||
|
||||
@ -117,7 +118,7 @@ Map<String, dynamic> requestModelToHARJsonRequest(
|
||||
hasBody = true;
|
||||
json["postData"] = {};
|
||||
json["postData"]["mimeType"] =
|
||||
kContentTypeMap[requestModel.requestBodyContentType] ?? "";
|
||||
requestModel.requestBodyContentType.header;
|
||||
json["postData"]["text"] = requestBody;
|
||||
if (exportMode) {
|
||||
json["postData"]["comment"] = "";
|
||||
@ -125,14 +126,17 @@ Map<String, dynamic> requestModelToHARJsonRequest(
|
||||
}
|
||||
}
|
||||
|
||||
var headersList = requestModel.requestHeaders;
|
||||
var headersList = useEnabled
|
||||
? requestModel.enabledRequestHeaders
|
||||
: requestModel.requestHeaders;
|
||||
if (headersList != null || hasBody) {
|
||||
var headers = requestModel.headersMap;
|
||||
var headers =
|
||||
useEnabled ? requestModel.enabledHeadersMap : requestModel.headersMap;
|
||||
if (headers.isNotEmpty || hasBody) {
|
||||
if (hasBody) {
|
||||
if (hasBody && !requestModel.hasContentTypeHeader) {
|
||||
var m = {
|
||||
"name": "Content-Type",
|
||||
"value": kContentTypeMap[requestModel.requestBodyContentType] ?? ""
|
||||
"value": requestModel.requestBodyContentType.header
|
||||
};
|
||||
if (exportMode) {
|
||||
m["comment"] = "";
|
||||
@ -148,7 +152,9 @@ Map<String, dynamic> requestModelToHARJsonRequest(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requestModel.isFormDataRequest) {
|
||||
json["formData"] = requestModel.formDataMapList;
|
||||
}
|
||||
if (exportMode) {
|
||||
json["comment"] = "";
|
||||
json["cookies"] = [];
|
||||
|
@ -2,19 +2,37 @@ Map<String, String> headers = {
|
||||
"Accept": "Specifies the media types that are acceptable for the response.",
|
||||
"Accept-Encoding":
|
||||
"Indicates the encoding methods the client can understand.",
|
||||
"Access-Control-Allow-Headers":
|
||||
"Specifies a list of HTTP headers that can be used in an actual request after a preflight request including the Access-Control-Request-Headers header is made.",
|
||||
"Access-Control-Allow-Methods":
|
||||
"Specifies a list of HTTP request methods allowed during CORS. ",
|
||||
"Access-Control-Allow-Origin":
|
||||
"Indicates whether the response can be shared with the requesting code from the given origin.",
|
||||
"Access-Control-Max-Age":
|
||||
"Indicates the maximum amount of time the results of a preflight request can be cached.",
|
||||
"Access-Control-Request-Headers":
|
||||
"Used in preflight requests during CORS to specify the headers that will be included in the actual request.",
|
||||
"Access-Control-Request-Method":
|
||||
"Used in preflight requests during CORS to indicate the HTTP method that will be used in the actual request.",
|
||||
"Accept-Language":
|
||||
"Specifies the preferred natural language and locale for the response.",
|
||||
"Authorization":
|
||||
"Contains credentials for authenticating the client with the server.",
|
||||
"Authorization Bearer Token": "Often used for token-based authentication.",
|
||||
"Cache-Control":
|
||||
"Provides directives for caching mechanisms in both requests and responses.",
|
||||
"Connection":
|
||||
"Informs whether the connection stays open or close after the current transaction finishes.",
|
||||
"Content-Disposition":
|
||||
"Specifies the presentation style (inline or attachment) of the response.",
|
||||
"Content-Encoding":
|
||||
"Indicates the encoding transformations that have been applied to the entity body of the response.",
|
||||
"Content-Length":
|
||||
"Indicates the size of the message body sent to the recipient in bytes.",
|
||||
"Content-Security-Policy":
|
||||
"Controls the sources from which content can be loaded on a web page to mitigate various types of attacks.",
|
||||
"Content-Type":
|
||||
"Indicates the original media type of the resource (prior to any content encoding applied for sending)",
|
||||
"Cookie": "Used to send previously stored cookies back to the server.",
|
||||
"Cross-Origin-Embedder-Policy":
|
||||
"Controls whether a document is allowed to be embedded in another document.",
|
||||
@ -22,9 +40,12 @@ Map<String, String> headers = {
|
||||
"Controls which documents are allowed to open a new window or access the current window.",
|
||||
"Cross-Origin-Resource-Policy":
|
||||
"Controls how cross-origin requests for resources are handled.",
|
||||
"Date": "Indicates the date and time at which the message was sent.",
|
||||
"DNT":
|
||||
"Informs websites whether the user's preference is to opt out of online tracking.",
|
||||
"Expect": "Indicates certain expectations that need to be met by the server.",
|
||||
"Expires":
|
||||
"Contains the date/time after which the response is considered expired",
|
||||
"Host": "Specifies the domain name of the server and the port number.",
|
||||
"If-Match":
|
||||
"Used for conditional requests, allows the server to respond based on certain conditions.",
|
||||
@ -36,6 +57,8 @@ Map<String, String> headers = {
|
||||
"Used in conjunction with the Range header to conditionally request a partial resource.",
|
||||
"If-Unmodified-Since":
|
||||
"Used for conditional requests, allows the server to respond based on certain conditions.",
|
||||
"Location":
|
||||
"Indicates the URL a client should redirect to for further interaction.",
|
||||
"Origin": "Specifies the origin of a cross-origin request.",
|
||||
"Range":
|
||||
"Used to request only part of a resource, typically in the context of downloading large files.",
|
||||
@ -45,6 +68,7 @@ Map<String, String> headers = {
|
||||
"Specifies how much information the browser should include in the Referer header when navigating to other pages.",
|
||||
"Retry-After":
|
||||
"Informs the client how long it should wait before making another request after a server has responded with a rate-limiting status code.",
|
||||
"Server": "Indicates the software used by the origin server.",
|
||||
"Strict-Transport-Security":
|
||||
"Instructs the browser to always use HTTPS for the given domain.",
|
||||
"TE": "Specifies the transfer encodings that are acceptable to the client.",
|
||||
@ -53,10 +77,14 @@ Map<String, String> headers = {
|
||||
"Via":
|
||||
"Indicates intermediate proxies or gateways through which the request or response has passed.",
|
||||
"X-Api-Key": "Used to authenticate requests to an API with an API key.",
|
||||
"X-Content-Type-Options":
|
||||
"Used to prevent browsers from MIME-sniffing a response.",
|
||||
"X-CSRF-Token":
|
||||
"Used for protection against Cross-Site Request Forgery (CSRF) attacks.",
|
||||
"X-Forwarded-For":
|
||||
"Identifies the client's original IP address when behind a proxy or load balancer.",
|
||||
"X-Frame-Options":
|
||||
"Controls whether a webpage can be displayed within an iframe or other embedded frame elements.",
|
||||
"X-Requested-With":
|
||||
"Indicates whether the request was made with JavaScript using XMLHttpRequest.",
|
||||
"X-XSS-Protection":
|
||||
|
@ -59,3 +59,13 @@ Color getDarkModeColor(Color col) {
|
||||
kColorWhite,
|
||||
);
|
||||
}
|
||||
|
||||
double? getJsonPreviewerMaxRootNodeWidth(double w) {
|
||||
if (w < 300) {
|
||||
return 150;
|
||||
}
|
||||
if (w < 400) {
|
||||
return 200;
|
||||
}
|
||||
return w - 150;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import 'package:apidash/utils/utils.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import "snackbars.dart";
|
||||
|
||||
class CopyButton extends StatefulWidget {
|
||||
class CopyButton extends StatelessWidget {
|
||||
const CopyButton({
|
||||
super.key,
|
||||
required this.toCopy,
|
||||
@ -15,21 +15,16 @@ class CopyButton extends StatefulWidget {
|
||||
final String toCopy;
|
||||
final bool showLabel;
|
||||
|
||||
@override
|
||||
State<CopyButton> createState() => _CopyButtonState();
|
||||
}
|
||||
|
||||
class _CopyButtonState extends State<CopyButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var sm = ScaffoldMessenger.of(context);
|
||||
return Tooltip(
|
||||
message: widget.showLabel ? '' : kLabelCopy,
|
||||
message: showLabel ? '' : kLabelCopy,
|
||||
child: SizedBox(
|
||||
width: widget.showLabel ? null : kTextButtonMinWidth,
|
||||
width: showLabel ? null : kTextButtonMinWidth,
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
await Clipboard.setData(ClipboardData(text: widget.toCopy));
|
||||
await Clipboard.setData(ClipboardData(text: toCopy));
|
||||
sm.hideCurrentSnackBar();
|
||||
sm.showSnackBar(getSnackBar("Copied"));
|
||||
},
|
||||
@ -40,7 +35,7 @@ class _CopyButtonState extends State<CopyButton> {
|
||||
Icons.content_copy,
|
||||
size: 20,
|
||||
),
|
||||
if (widget.showLabel) const Text(kLabelCopy)
|
||||
if (showLabel) const Text(kLabelCopy)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -49,7 +44,7 @@ class _CopyButtonState extends State<CopyButton> {
|
||||
}
|
||||
}
|
||||
|
||||
class SendRequestButton extends StatefulWidget {
|
||||
class SendRequestButton extends StatelessWidget {
|
||||
const SendRequestButton({
|
||||
super.key,
|
||||
required this.activeId,
|
||||
@ -61,29 +56,17 @@ class SendRequestButton extends StatefulWidget {
|
||||
final String? sentRequestId;
|
||||
final void Function() onTap;
|
||||
|
||||
@override
|
||||
State<SendRequestButton> createState() => _SendRequestButtonState();
|
||||
}
|
||||
|
||||
class _SendRequestButtonState extends State<SendRequestButton> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool disable = widget.sentRequestId != null;
|
||||
bool disable = sentRequestId != null;
|
||||
return FilledButton(
|
||||
onPressed: disable ? null : widget.onTap,
|
||||
onPressed: disable ? null : onTap,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
disable
|
||||
? (widget.activeId == widget.sentRequestId
|
||||
? kLabelSending
|
||||
: kLabelBusy)
|
||||
? (activeId == sentRequestId ? kLabelSending : kLabelBusy)
|
||||
: kLabelSend,
|
||||
style: kTextStyleButton,
|
||||
),
|
||||
@ -99,7 +82,7 @@ class _SendRequestButtonState extends State<SendRequestButton> {
|
||||
}
|
||||
}
|
||||
|
||||
class SaveInDownloadsButton extends StatefulWidget {
|
||||
class SaveInDownloadsButton extends StatelessWidget {
|
||||
const SaveInDownloadsButton({
|
||||
super.key,
|
||||
this.content,
|
||||
@ -115,29 +98,24 @@ class SaveInDownloadsButton extends StatefulWidget {
|
||||
final String? name;
|
||||
final bool showLabel;
|
||||
|
||||
@override
|
||||
State<SaveInDownloadsButton> createState() => _SaveInDownloadsButtonState();
|
||||
}
|
||||
|
||||
class _SaveInDownloadsButtonState extends State<SaveInDownloadsButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var sm = ScaffoldMessenger.of(context);
|
||||
return Tooltip(
|
||||
message: widget.showLabel ? '' : kLabelDownload,
|
||||
message: showLabel ? '' : kLabelDownload,
|
||||
child: SizedBox(
|
||||
width: widget.showLabel ? null : kTextButtonMinWidth,
|
||||
width: showLabel ? null : kTextButtonMinWidth,
|
||||
child: TextButton(
|
||||
onPressed: (widget.content != null)
|
||||
onPressed: (content != null)
|
||||
? () async {
|
||||
var message = "";
|
||||
var path = await getFileDownloadpath(
|
||||
widget.name,
|
||||
widget.ext ?? getFileExtension(widget.mimeType),
|
||||
name,
|
||||
ext ?? getFileExtension(mimeType),
|
||||
);
|
||||
if (path != null) {
|
||||
try {
|
||||
await saveFile(path, widget.content!);
|
||||
await saveFile(path, content!);
|
||||
var sp = getShortPath(path);
|
||||
message = 'Saved to $sp';
|
||||
} catch (e) {
|
||||
@ -157,7 +135,7 @@ class _SaveInDownloadsButtonState extends State<SaveInDownloadsButton> {
|
||||
Icons.download,
|
||||
size: 20,
|
||||
),
|
||||
if (widget.showLabel) const Text(kLabelDownload)
|
||||
if (showLabel) const Text(kLabelDownload)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -166,7 +144,7 @@ class _SaveInDownloadsButtonState extends State<SaveInDownloadsButton> {
|
||||
}
|
||||
}
|
||||
|
||||
class RepoButton extends StatefulWidget {
|
||||
class RepoButton extends StatelessWidget {
|
||||
const RepoButton({
|
||||
super.key,
|
||||
this.text,
|
||||
@ -176,15 +154,10 @@ class RepoButton extends StatefulWidget {
|
||||
final String? text;
|
||||
final IconData? icon;
|
||||
|
||||
@override
|
||||
State<RepoButton> createState() => _RepoButtonState();
|
||||
}
|
||||
|
||||
class _RepoButtonState extends State<RepoButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var label = widget.text ?? "GitHub";
|
||||
if (widget.icon == null) {
|
||||
var label = text ?? "GitHub";
|
||||
if (icon == null) {
|
||||
return FilledButton(
|
||||
onPressed: () {
|
||||
launchUrl(Uri.parse(kGitUrl));
|
||||
@ -200,7 +173,7 @@ class _RepoButtonState extends State<RepoButton> {
|
||||
launchUrl(Uri.parse(kGitUrl));
|
||||
},
|
||||
icon: Icon(
|
||||
widget.icon,
|
||||
icon,
|
||||
size: 20.0,
|
||||
),
|
||||
label: Text(
|
||||
@ -211,7 +184,7 @@ class _RepoButtonState extends State<RepoButton> {
|
||||
}
|
||||
}
|
||||
|
||||
class DiscordButton extends StatefulWidget {
|
||||
class DiscordButton extends StatelessWidget {
|
||||
const DiscordButton({
|
||||
super.key,
|
||||
this.text,
|
||||
@ -219,14 +192,9 @@ class DiscordButton extends StatefulWidget {
|
||||
|
||||
final String? text;
|
||||
|
||||
@override
|
||||
State<DiscordButton> createState() => _DiscordButtonState();
|
||||
}
|
||||
|
||||
class _DiscordButtonState extends State<DiscordButton> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var label = widget.text ?? 'Discord Server';
|
||||
var label = text ?? 'Discord Server';
|
||||
return FilledButton.icon(
|
||||
onPressed: () {
|
||||
launchUrl(Uri.parse(kDiscordUrl));
|
||||
@ -242,3 +210,27 @@ class _DiscordButtonState extends State<DiscordButton> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SaveButton extends StatelessWidget {
|
||||
const SaveButton({
|
||||
super.key,
|
||||
this.onPressed,
|
||||
});
|
||||
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextButton.icon(
|
||||
onPressed: onPressed,
|
||||
icon: const Icon(
|
||||
Icons.save,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text(
|
||||
kLabelSave,
|
||||
style: kTextStyleButton,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -129,15 +129,11 @@ class SidebarRequestCard extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class RequestDetailsCard extends StatefulWidget {
|
||||
class RequestDetailsCard extends StatelessWidget {
|
||||
const RequestDetailsCard({super.key, this.child});
|
||||
|
||||
final Widget? child;
|
||||
@override
|
||||
State<RequestDetailsCard> createState() => _RequestDetailsCardState();
|
||||
}
|
||||
|
||||
class _RequestDetailsCardState extends State<RequestDetailsCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
@ -148,7 +144,7 @@ class _RequestDetailsCardState extends State<RequestDetailsCard> {
|
||||
borderRadius: kBorderRadius12,
|
||||
),
|
||||
elevation: 0,
|
||||
child: widget.child,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
41
lib/widgets/checkbox.dart
Normal file
41
lib/widgets/checkbox.dart
Normal file
@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CheckBox extends StatelessWidget {
|
||||
final String keyId;
|
||||
final bool value;
|
||||
final ValueChanged<bool?> onChanged;
|
||||
final ColorScheme? colorScheme;
|
||||
const CheckBox({
|
||||
super.key,
|
||||
required this.keyId,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
this.colorScheme,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var colorScheme = this.colorScheme ?? Theme.of(context).colorScheme;
|
||||
return Checkbox(
|
||||
key: Key(keyId),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(3),
|
||||
),
|
||||
side: BorderSide(
|
||||
color: colorScheme.surfaceVariant,
|
||||
width: 1.5,
|
||||
),
|
||||
splashRadius: 0,
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
checkColor: colorScheme.onPrimary,
|
||||
fillColor: MaterialStateProperty.resolveWith<Color?>(
|
||||
(Set<MaterialState> states) {
|
||||
if (states.contains(MaterialState.selected)) {
|
||||
return colorScheme.primary;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
@ -97,7 +97,7 @@ List<TextSpan> generateSpans(
|
||||
return spans;
|
||||
}
|
||||
|
||||
class ViewCodePane extends StatefulWidget {
|
||||
class ViewCodePane extends StatelessWidget {
|
||||
const ViewCodePane({
|
||||
super.key,
|
||||
required this.code,
|
||||
@ -109,11 +109,6 @@ class ViewCodePane extends StatefulWidget {
|
||||
final CodegenLanguage codegenLanguage;
|
||||
final Function(CodegenLanguage?) onChangedCodegenLanguage;
|
||||
|
||||
@override
|
||||
State<ViewCodePane> createState() => _ViewCodePaneState();
|
||||
}
|
||||
|
||||
class _ViewCodePaneState extends State<ViewCodePane> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var codeTheme = Theme.of(context).brightness == Brightness.light
|
||||
@ -145,17 +140,17 @@ class _ViewCodePaneState extends State<ViewCodePane> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: DropdownButtonCodegenLanguage(
|
||||
codegenLanguage: widget.codegenLanguage,
|
||||
onChanged: widget.onChangedCodegenLanguage,
|
||||
codegenLanguage: codegenLanguage,
|
||||
onChanged: onChangedCodegenLanguage,
|
||||
),
|
||||
),
|
||||
CopyButton(
|
||||
toCopy: widget.code,
|
||||
toCopy: code,
|
||||
showLabel: showLabel,
|
||||
),
|
||||
SaveInDownloadsButton(
|
||||
content: stringToBytes(widget.code),
|
||||
ext: widget.codegenLanguage.ext,
|
||||
content: stringToBytes(code),
|
||||
ext: codegenLanguage.ext,
|
||||
showLabel: showLabel,
|
||||
)
|
||||
],
|
||||
@ -168,9 +163,9 @@ class _ViewCodePaneState extends State<ViewCodePane> {
|
||||
padding: kP8,
|
||||
decoration: textContainerdecoration,
|
||||
child: CodeGenPreviewer(
|
||||
code: widget.code,
|
||||
code: code,
|
||||
theme: codeTheme,
|
||||
language: widget.codegenLanguage.codeHighlightLang,
|
||||
language: codegenLanguage.codeHighlightLang,
|
||||
textStyle: kCodeStyle,
|
||||
),
|
||||
),
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:apidash/utils/utils.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class DropdownButtonHttpMethod extends StatefulWidget {
|
||||
class DropdownButtonHttpMethod extends StatelessWidget {
|
||||
const DropdownButtonHttpMethod({
|
||||
super.key,
|
||||
this.method,
|
||||
@ -12,30 +12,19 @@ class DropdownButtonHttpMethod extends StatefulWidget {
|
||||
final HTTPVerb? method;
|
||||
final void Function(HTTPVerb? value)? onChanged;
|
||||
|
||||
@override
|
||||
State<DropdownButtonHttpMethod> createState() =>
|
||||
_DropdownButtonHttpMethodState();
|
||||
}
|
||||
|
||||
class _DropdownButtonHttpMethodState extends State<DropdownButtonHttpMethod> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final surfaceColor = Theme.of(context).colorScheme.surface;
|
||||
return DropdownButton<HTTPVerb>(
|
||||
focusColor: surfaceColor,
|
||||
value: widget.method,
|
||||
value: method,
|
||||
icon: const Icon(Icons.unfold_more_rounded),
|
||||
elevation: 4,
|
||||
underline: Container(
|
||||
height: 0,
|
||||
),
|
||||
borderRadius: kBorderRadius12,
|
||||
onChanged: widget.onChanged,
|
||||
onChanged: onChanged,
|
||||
items: HTTPVerb.values.map<DropdownMenuItem<HTTPVerb>>((HTTPVerb value) {
|
||||
return DropdownMenuItem<HTTPVerb>(
|
||||
value: value,
|
||||
@ -58,7 +47,7 @@ class _DropdownButtonHttpMethodState extends State<DropdownButtonHttpMethod> {
|
||||
}
|
||||
}
|
||||
|
||||
class DropdownButtonContentType extends StatefulWidget {
|
||||
class DropdownButtonContentType extends StatelessWidget {
|
||||
const DropdownButtonContentType({
|
||||
super.key,
|
||||
this.contentType,
|
||||
@ -68,18 +57,12 @@ class DropdownButtonContentType extends StatefulWidget {
|
||||
final ContentType? contentType;
|
||||
final void Function(ContentType?)? onChanged;
|
||||
|
||||
@override
|
||||
State<DropdownButtonContentType> createState() =>
|
||||
_DropdownButtonContentTypeState();
|
||||
}
|
||||
|
||||
class _DropdownButtonContentTypeState extends State<DropdownButtonContentType> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final surfaceColor = Theme.of(context).colorScheme.surface;
|
||||
return DropdownButton<ContentType>(
|
||||
focusColor: surfaceColor,
|
||||
value: widget.contentType,
|
||||
value: contentType,
|
||||
icon: const Icon(
|
||||
Icons.unfold_more_rounded,
|
||||
size: 16,
|
||||
@ -91,7 +74,7 @@ class _DropdownButtonContentTypeState extends State<DropdownButtonContentType> {
|
||||
underline: Container(
|
||||
height: 0,
|
||||
),
|
||||
onChanged: widget.onChanged,
|
||||
onChanged: onChanged,
|
||||
borderRadius: kBorderRadius12,
|
||||
items: ContentType.values
|
||||
.map<DropdownMenuItem<ContentType>>((ContentType value) {
|
||||
@ -110,28 +93,72 @@ class _DropdownButtonContentTypeState extends State<DropdownButtonContentType> {
|
||||
}
|
||||
}
|
||||
|
||||
class DropdownButtonCodegenLanguage extends StatefulWidget {
|
||||
class DropdownButtonFormData extends StatefulWidget {
|
||||
const DropdownButtonFormData({
|
||||
super.key,
|
||||
this.formDataType,
|
||||
this.onChanged,
|
||||
});
|
||||
|
||||
final FormDataType? formDataType;
|
||||
final void Function(FormDataType?)? onChanged;
|
||||
|
||||
@override
|
||||
State<DropdownButtonFormData> createState() => _DropdownButtonFormData();
|
||||
}
|
||||
|
||||
class _DropdownButtonFormData extends State<DropdownButtonFormData> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final surfaceColor = Theme.of(context).colorScheme.surface;
|
||||
return DropdownButton<FormDataType>(
|
||||
dropdownColor: surfaceColor,
|
||||
focusColor: surfaceColor,
|
||||
value: widget.formDataType,
|
||||
icon: const Icon(
|
||||
Icons.unfold_more_rounded,
|
||||
size: 16,
|
||||
),
|
||||
elevation: 4,
|
||||
style: kCodeStyle.copyWith(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
underline: const IgnorePointer(),
|
||||
onChanged: widget.onChanged,
|
||||
borderRadius: kBorderRadius12,
|
||||
items: FormDataType.values
|
||||
.map<DropdownMenuItem<FormDataType>>((FormDataType value) {
|
||||
return DropdownMenuItem<FormDataType>(
|
||||
value: value,
|
||||
child: Padding(
|
||||
padding: kPs8,
|
||||
child: Text(
|
||||
value.name,
|
||||
style: kTextStyleButton,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DropdownButtonCodegenLanguage extends StatelessWidget {
|
||||
const DropdownButtonCodegenLanguage({
|
||||
super.key,
|
||||
this.codegenLanguage,
|
||||
this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<DropdownButtonCodegenLanguage> createState() =>
|
||||
_DropdownButtonCodegenLanguageState();
|
||||
final CodegenLanguage? codegenLanguage;
|
||||
final void Function(CodegenLanguage?)? onChanged;
|
||||
}
|
||||
|
||||
class _DropdownButtonCodegenLanguageState
|
||||
extends State<DropdownButtonCodegenLanguage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final surfaceColor = Theme.of(context).colorScheme.surface;
|
||||
return DropdownButton<CodegenLanguage>(
|
||||
focusColor: surfaceColor,
|
||||
value: widget.codegenLanguage,
|
||||
value: codegenLanguage,
|
||||
icon: const Icon(
|
||||
Icons.unfold_more_rounded,
|
||||
size: 16,
|
||||
@ -143,7 +170,7 @@ class _DropdownButtonCodegenLanguageState
|
||||
underline: Container(
|
||||
height: 0,
|
||||
),
|
||||
onChanged: widget.onChanged,
|
||||
onChanged: onChanged,
|
||||
borderRadius: kBorderRadius12,
|
||||
items: CodegenLanguage.values
|
||||
.map<DropdownMenuItem<CodegenLanguage>>((CodegenLanguage value) {
|
||||
|
81
lib/widgets/form_data_field.dart
Normal file
81
lib/widgets/form_data_field.dart
Normal file
@ -0,0 +1,81 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FormDataField extends StatefulWidget {
|
||||
const FormDataField({
|
||||
super.key,
|
||||
required this.keyId,
|
||||
this.initialValue,
|
||||
this.hintText,
|
||||
this.onChanged,
|
||||
this.colorScheme,
|
||||
this.formDataType,
|
||||
this.onFormDataTypeChanged,
|
||||
});
|
||||
|
||||
final String keyId;
|
||||
final String? initialValue;
|
||||
final String? hintText;
|
||||
final void Function(String)? onChanged;
|
||||
final ColorScheme? colorScheme;
|
||||
final FormDataType? formDataType;
|
||||
final void Function(FormDataType?)? onFormDataTypeChanged;
|
||||
|
||||
@override
|
||||
State<FormDataField> createState() => _FormDataFieldState();
|
||||
}
|
||||
|
||||
class _FormDataFieldState extends State<FormDataField> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var colorScheme = widget.colorScheme ?? Theme.of(context).colorScheme;
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: TextFormField(
|
||||
initialValue: widget.initialValue,
|
||||
key: Key(widget.keyId),
|
||||
style: kCodeStyle.copyWith(
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: kCodeStyle.copyWith(
|
||||
color: colorScheme.outline.withOpacity(
|
||||
kHintOpacity,
|
||||
),
|
||||
),
|
||||
hintText: widget.hintText,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary.withOpacity(
|
||||
kHintOpacity,
|
||||
),
|
||||
),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceVariant,
|
||||
),
|
||||
),
|
||||
suffixIcon: DropdownButtonFormData(
|
||||
formDataType: widget.formDataType,
|
||||
onChanged: (p0) {
|
||||
if (widget.onFormDataTypeChanged != null) {
|
||||
widget.onFormDataTypeChanged!(p0);
|
||||
}
|
||||
},
|
||||
)),
|
||||
onChanged: widget.onChanged,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -5,16 +5,11 @@ import '../consts.dart';
|
||||
import 'markdown.dart';
|
||||
import 'error_message.dart';
|
||||
|
||||
class IntroMessage extends StatefulWidget {
|
||||
class IntroMessage extends StatelessWidget {
|
||||
const IntroMessage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<IntroMessage> createState() => _IntroMessageState();
|
||||
}
|
||||
|
||||
class _IntroMessageState extends State<IntroMessage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
late String text;
|
||||
|
@ -5,6 +5,7 @@ import 'package:provider/provider.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
import '../consts.dart';
|
||||
import '../utils/ui_utils.dart';
|
||||
import "snackbars.dart";
|
||||
import 'textfields.dart';
|
||||
|
||||
@ -151,13 +152,26 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
store.expandAll();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(JsonPreviewer oldWidget) {
|
||||
if (oldWidget.code != widget.code) {
|
||||
store.buildNodes(widget.code, areAllCollapsed: true);
|
||||
store.expandAll();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var sm = ScaffoldMessenger.of(context);
|
||||
return ChangeNotifierProvider.value(
|
||||
value: store,
|
||||
child: Consumer<DataExplorerStore>(
|
||||
builder: (context, state, child) => Column(
|
||||
builder: (context, state, child) {
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
var maxRootNodeWidth =
|
||||
getJsonPreviewerMaxRootNodeWidth(constraints.maxWidth);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
@ -167,15 +181,26 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
onPressed: () async {
|
||||
await _copy(kEncoder.convert(widget.code), sm);
|
||||
},
|
||||
child: const Text('Copy'),
|
||||
child: const Text(
|
||||
'Copy',
|
||||
style: kTextStyleButtonSmall,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: state.areAllExpanded() ? null : state.expandAll,
|
||||
child: const Text('Expand All'),
|
||||
onPressed:
|
||||
state.areAllExpanded() ? null : state.expandAll,
|
||||
child: const Text(
|
||||
'Expand All',
|
||||
style: kTextStyleButtonSmall,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: state.areAllCollapsed() ? null : state.collapseAll,
|
||||
child: const Text('Collapse All'),
|
||||
onPressed:
|
||||
state.areAllCollapsed() ? null : state.collapseAll,
|
||||
child: const Text(
|
||||
'Collapse All',
|
||||
style: kTextStyleButtonSmall,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -186,7 +211,8 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
itemSpacing: 4,
|
||||
rootInformationBuilder: (context, node) =>
|
||||
rootInfoBox(context, node),
|
||||
collapsableToggleBuilder: (context, node) => AnimatedRotation(
|
||||
collapsableToggleBuilder: (context, node) =>
|
||||
AnimatedRotation(
|
||||
turns: node.isCollapsed ? -0.25 : 0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: const Icon(Icons.arrow_drop_down),
|
||||
@ -196,13 +222,15 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(maxHeight: 18),
|
||||
constraints:
|
||||
const BoxConstraints(maxHeight: 18),
|
||||
icon: const Icon(
|
||||
Icons.copy,
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () async {
|
||||
await _copy(kEncoder.convert(toJson(node)), sm);
|
||||
await _copy(
|
||||
kEncoder.convert(toJson(node)), sm);
|
||||
},
|
||||
),
|
||||
)
|
||||
@ -212,6 +240,7 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
theme: (Theme.of(context).brightness == Brightness.light)
|
||||
? dataExplorerThemeLight
|
||||
: dataExplorerThemeDark,
|
||||
maxRootNodeWidth: maxRootNodeWidth,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
@ -264,7 +293,10 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -333,7 +365,7 @@ class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
horizontal: 4,
|
||||
vertical: 2,
|
||||
),
|
||||
child: Text(
|
||||
child: SelectableText(
|
||||
node.isClass ? '{${node.childrenCount}}' : '[${node.childrenCount}]',
|
||||
style: kCodeStyle,
|
||||
),
|
||||
|
@ -4,7 +4,7 @@ import 'package:markdown/markdown.dart' as md;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'buttons.dart';
|
||||
|
||||
class CustomMarkdown extends StatefulWidget {
|
||||
class CustomMarkdown extends StatelessWidget {
|
||||
const CustomMarkdown({
|
||||
super.key,
|
||||
required this.data,
|
||||
@ -13,11 +13,6 @@ class CustomMarkdown extends StatefulWidget {
|
||||
final String data;
|
||||
final EdgeInsets padding;
|
||||
|
||||
@override
|
||||
State<CustomMarkdown> createState() => _CustomMarkdownState();
|
||||
}
|
||||
|
||||
class _CustomMarkdownState extends State<CustomMarkdown> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final mdStyleSheet = MarkdownStyleSheet(
|
||||
@ -25,9 +20,9 @@ class _CustomMarkdownState extends State<CustomMarkdown> {
|
||||
p: Theme.of(context).textTheme.titleMedium,
|
||||
);
|
||||
return Markdown(
|
||||
padding: widget.padding,
|
||||
padding: padding,
|
||||
styleSheet: mdStyleSheet,
|
||||
data: widget.data,
|
||||
data: data,
|
||||
selectable: true,
|
||||
extensionSet: md.ExtensionSet.gitHubFlavored,
|
||||
onTapLink: (text, href, title) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class RequestCardMenu extends StatefulWidget {
|
||||
class RequestCardMenu extends StatelessWidget {
|
||||
const RequestCardMenu({
|
||||
super.key,
|
||||
this.onSelected,
|
||||
@ -9,18 +9,13 @@ class RequestCardMenu extends StatefulWidget {
|
||||
|
||||
final Function(RequestItemMenuOption)? onSelected;
|
||||
|
||||
@override
|
||||
State<RequestCardMenu> createState() => _RequestCardMenuState();
|
||||
}
|
||||
|
||||
class _RequestCardMenuState extends State<RequestCardMenu> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopupMenuButton<RequestItemMenuOption>(
|
||||
padding: EdgeInsets.zero,
|
||||
splashRadius: 14,
|
||||
iconSize: 14,
|
||||
onSelected: widget.onSelected,
|
||||
onSelected: onSelected,
|
||||
itemBuilder: (BuildContext context) =>
|
||||
<PopupMenuEntry<RequestItemMenuOption>>[
|
||||
const PopupMenuItem<RequestItemMenuOption>(
|
||||
|
@ -1,11 +1,13 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'error_message.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:printing/printing.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:vector_graphics_compiler/vector_graphics_compiler.dart';
|
||||
import 'error_message.dart';
|
||||
import 'uint8_audio_player.dart';
|
||||
import 'json_previewer.dart';
|
||||
import '../consts.dart';
|
||||
|
||||
class Previewer extends StatefulWidget {
|
||||
const Previewer({
|
||||
@ -40,6 +42,18 @@ class _PreviewerState extends State<Previewer> {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
if (widget.type == kTypeImage && widget.subtype == kSubTypeSvg) {
|
||||
final String rawSvg = widget.body;
|
||||
try {
|
||||
parseWithoutOptimizers(rawSvg);
|
||||
var svgImg = SvgPicture.string(
|
||||
rawSvg,
|
||||
);
|
||||
return svgImg;
|
||||
} catch (e) {
|
||||
return const ErrorMessage(message: kSvgError);
|
||||
}
|
||||
}
|
||||
if (widget.type == kTypeImage) {
|
||||
return Image.memory(
|
||||
widget.bytes,
|
||||
|
@ -50,7 +50,7 @@ class SendingWidget extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class ResponsePaneHeader extends StatefulWidget {
|
||||
class ResponsePaneHeader extends StatelessWidget {
|
||||
const ResponsePaneHeader({
|
||||
super.key,
|
||||
this.responseStatus,
|
||||
@ -61,11 +61,7 @@ class ResponsePaneHeader extends StatefulWidget {
|
||||
final int? responseStatus;
|
||||
final String? message;
|
||||
final Duration? time;
|
||||
@override
|
||||
State<ResponsePaneHeader> createState() => _ResponsePaneHeaderState();
|
||||
}
|
||||
|
||||
class _ResponsePaneHeaderState extends State<ResponsePaneHeader> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
@ -82,10 +78,10 @@ class _ResponsePaneHeaderState extends State<ResponsePaneHeader> {
|
||||
text: "Response (",
|
||||
),
|
||||
TextSpan(
|
||||
text: "${widget.responseStatus}",
|
||||
text: "$responseStatus",
|
||||
style: TextStyle(
|
||||
color: getResponseStatusCodeColor(
|
||||
widget.responseStatus,
|
||||
responseStatus,
|
||||
brightness: Theme.of(context).brightness,
|
||||
),
|
||||
fontFamily: kCodeStyle.fontFamily,
|
||||
@ -101,13 +97,13 @@ class _ResponsePaneHeaderState extends State<ResponsePaneHeader> {
|
||||
kHSpacer20,
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.message ?? "",
|
||||
message ?? "",
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
fontFamily: kCodeStyle.fontFamily,
|
||||
color: getResponseStatusCodeColor(
|
||||
widget.responseStatus,
|
||||
responseStatus,
|
||||
brightness: Theme.of(context).brightness,
|
||||
),
|
||||
),
|
||||
@ -115,7 +111,7 @@ class _ResponsePaneHeaderState extends State<ResponsePaneHeader> {
|
||||
),
|
||||
kHSpacer20,
|
||||
Text(
|
||||
humanizeDuration(widget.time),
|
||||
humanizeDuration(time),
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
fontFamily: kCodeStyle.fontFamily,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
@ -208,7 +204,7 @@ class _ResponseTabViewState extends State<ResponseTabView>
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseHeadersHeader extends StatefulWidget {
|
||||
class ResponseHeadersHeader extends StatelessWidget {
|
||||
const ResponseHeadersHeader({
|
||||
super.key,
|
||||
required this.map,
|
||||
@ -217,11 +213,7 @@ class ResponseHeadersHeader extends StatefulWidget {
|
||||
|
||||
final Map map;
|
||||
final String name;
|
||||
@override
|
||||
State<ResponseHeadersHeader> createState() => _ResponseHeadersHeaderState();
|
||||
}
|
||||
|
||||
class _ResponseHeadersHeaderState extends State<ResponseHeadersHeader> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
@ -230,15 +222,15 @@ class _ResponseHeadersHeaderState extends State<ResponseHeadersHeader> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
"${widget.name} (${widget.map.length} items)",
|
||||
"$name (${map.length} items)",
|
||||
style: Theme.of(context).textTheme.labelLarge!.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.map.isNotEmpty)
|
||||
if (map.isNotEmpty)
|
||||
CopyButton(
|
||||
toCopy: kEncoder.convert(widget.map),
|
||||
toCopy: kEncoder.convert(map),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -248,7 +240,7 @@ class _ResponseHeadersHeaderState extends State<ResponseHeadersHeader> {
|
||||
|
||||
const kHeaderRow = ["Header Name", "Header Value"];
|
||||
|
||||
class ResponseHeaders extends StatefulWidget {
|
||||
class ResponseHeaders extends StatelessWidget {
|
||||
const ResponseHeaders({
|
||||
super.key,
|
||||
required this.responseHeaders,
|
||||
@ -257,11 +249,7 @@ class ResponseHeaders extends StatefulWidget {
|
||||
|
||||
final Map responseHeaders;
|
||||
final Map requestHeaders;
|
||||
@override
|
||||
State<ResponseHeaders> createState() => _ResponseHeadersState();
|
||||
}
|
||||
|
||||
class _ResponseHeadersState extends State<ResponseHeaders> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
@ -269,25 +257,25 @@ class _ResponseHeadersState extends State<ResponseHeaders> {
|
||||
child: ListView(
|
||||
children: [
|
||||
ResponseHeadersHeader(
|
||||
map: widget.responseHeaders,
|
||||
map: responseHeaders,
|
||||
name: "Response Headers",
|
||||
),
|
||||
if (widget.responseHeaders.isNotEmpty) kVSpacer5,
|
||||
if (widget.responseHeaders.isNotEmpty)
|
||||
if (responseHeaders.isNotEmpty) kVSpacer5,
|
||||
if (responseHeaders.isNotEmpty)
|
||||
MapTable(
|
||||
map: widget.responseHeaders,
|
||||
map: responseHeaders,
|
||||
colNames: kHeaderRow,
|
||||
firstColumnHeaderCase: true,
|
||||
),
|
||||
kVSpacer10,
|
||||
ResponseHeadersHeader(
|
||||
map: widget.requestHeaders,
|
||||
map: requestHeaders,
|
||||
name: "Request Headers",
|
||||
),
|
||||
if (widget.requestHeaders.isNotEmpty) kVSpacer5,
|
||||
if (widget.requestHeaders.isNotEmpty)
|
||||
if (requestHeaders.isNotEmpty) kVSpacer5,
|
||||
if (requestHeaders.isNotEmpty)
|
||||
MapTable(
|
||||
map: widget.requestHeaders,
|
||||
map: requestHeaders,
|
||||
colNames: kHeaderRow,
|
||||
firstColumnHeaderCase: true,
|
||||
),
|
||||
@ -297,21 +285,17 @@ class _ResponseHeadersState extends State<ResponseHeaders> {
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseBody extends StatefulWidget {
|
||||
class ResponseBody extends StatelessWidget {
|
||||
const ResponseBody({
|
||||
super.key,
|
||||
this.activeRequestModel,
|
||||
});
|
||||
|
||||
final RequestModel? activeRequestModel;
|
||||
@override
|
||||
State<ResponseBody> createState() => _ResponseBodyState();
|
||||
}
|
||||
|
||||
class _ResponseBodyState extends State<ResponseBody> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final responseModel = widget.activeRequestModel?.responseModel;
|
||||
final responseModel = activeRequestModel?.responseModel;
|
||||
if (responseModel == null) {
|
||||
return const ErrorMessage(
|
||||
message:
|
||||
@ -349,7 +333,7 @@ class _ResponseBodyState extends State<ResponseBody> {
|
||||
}
|
||||
|
||||
return BodySuccess(
|
||||
key: Key("${widget.activeRequestModel!.id}-response"),
|
||||
key: Key("${activeRequestModel!.id}-response"),
|
||||
mediaType: mediaType,
|
||||
options: options,
|
||||
bytes: responseModel.bodyBytes!,
|
||||
@ -416,23 +400,20 @@ class _BodySuccessState extends State<BodySuccess> {
|
||||
(widget.options == kRawBodyViewOptions)
|
||||
? const SizedBox()
|
||||
: SegmentedButton<ResponseBodyView>(
|
||||
selectedIcon: showLabel
|
||||
? Icon(
|
||||
kResponseBodyViewIcons[currentSeg]![kKeyIcon],
|
||||
)
|
||||
: null,
|
||||
style: const ButtonStyle(
|
||||
padding: MaterialStatePropertyAll(
|
||||
EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
),
|
||||
),
|
||||
),
|
||||
selectedIcon: Icon(currentSeg.icon),
|
||||
segments: widget.options
|
||||
.map<ButtonSegment<ResponseBodyView>>(
|
||||
(e) => ButtonSegment<ResponseBodyView>(
|
||||
value: e,
|
||||
label: showLabel
|
||||
? Text(
|
||||
kResponseBodyViewIcons[e]![kKeyName],
|
||||
)
|
||||
: null,
|
||||
icon: Icon(
|
||||
kResponseBodyViewIcons[e]![kKeyIcon],
|
||||
),
|
||||
label: Text(e.label),
|
||||
icon: Icon(e.icon),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:apidash/utils/utils.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class MapTable extends StatefulWidget {
|
||||
class MapTable extends StatelessWidget {
|
||||
const MapTable(
|
||||
{super.key,
|
||||
required this.map,
|
||||
@ -13,11 +13,6 @@ class MapTable extends StatefulWidget {
|
||||
final List<String> colNames;
|
||||
final bool firstColumnHeaderCase;
|
||||
|
||||
@override
|
||||
State<MapTable> createState() => _MapTableState();
|
||||
}
|
||||
|
||||
class _MapTableState extends State<MapTable> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Table(
|
||||
@ -33,7 +28,7 @@ class _MapTableState extends State<MapTable> {
|
||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||
children: [
|
||||
TableRow(
|
||||
children: widget.colNames
|
||||
children: colNames
|
||||
.map<TableCell>(
|
||||
(e) => TableCell(
|
||||
verticalAlignment: TableCellVerticalAlignment.top,
|
||||
@ -51,7 +46,7 @@ class _MapTableState extends State<MapTable> {
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
...widget.map.entries.map<TableRow>(
|
||||
...map.entries.map<TableRow>(
|
||||
(entry) => TableRow(
|
||||
children: [
|
||||
TableCell(
|
||||
@ -59,7 +54,7 @@ class _MapTableState extends State<MapTable> {
|
||||
child: Padding(
|
||||
padding: kP1,
|
||||
child: SelectableText(
|
||||
widget.firstColumnHeaderCase
|
||||
firstColumnHeaderCase
|
||||
? formatHeaderCase(entry.key)
|
||||
: entry.key,
|
||||
style: kCodeStyle.copyWith(
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class URLField extends StatefulWidget {
|
||||
class URLField extends StatelessWidget {
|
||||
const URLField({
|
||||
super.key,
|
||||
required this.activeId,
|
||||
@ -13,21 +13,11 @@ class URLField extends StatefulWidget {
|
||||
final String? initialValue;
|
||||
final void Function(String)? onChanged;
|
||||
|
||||
@override
|
||||
State<URLField> createState() => _URLFieldState();
|
||||
}
|
||||
|
||||
class _URLFieldState extends State<URLField> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
key: Key("url-${widget.activeId}"),
|
||||
initialValue: widget.initialValue,
|
||||
key: Key("url-$activeId"),
|
||||
initialValue: initialValue,
|
||||
style: kCodeStyle,
|
||||
decoration: InputDecoration(
|
||||
hintText: kHintTextUrlCard,
|
||||
@ -38,12 +28,12 @@ class _URLFieldState extends State<URLField> {
|
||||
),
|
||||
border: InputBorder.none,
|
||||
),
|
||||
onChanged: widget.onChanged,
|
||||
onChanged: onChanged,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CellField extends StatefulWidget {
|
||||
class CellField extends StatelessWidget {
|
||||
const CellField({
|
||||
super.key,
|
||||
required this.keyId,
|
||||
@ -59,41 +49,36 @@ class CellField extends StatefulWidget {
|
||||
final void Function(String)? onChanged;
|
||||
final ColorScheme? colorScheme;
|
||||
|
||||
@override
|
||||
State<CellField> createState() => _CellFieldState();
|
||||
}
|
||||
|
||||
class _CellFieldState extends State<CellField> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var colorScheme = widget.colorScheme ?? Theme.of(context).colorScheme;
|
||||
var clrScheme = colorScheme ?? Theme.of(context).colorScheme;
|
||||
return TextFormField(
|
||||
key: Key(widget.keyId),
|
||||
initialValue: widget.initialValue,
|
||||
key: Key(keyId),
|
||||
initialValue: initialValue,
|
||||
style: kCodeStyle.copyWith(
|
||||
color: colorScheme.onSurface,
|
||||
color: clrScheme.onSurface,
|
||||
),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: kCodeStyle.copyWith(
|
||||
color: colorScheme.outline.withOpacity(
|
||||
color: clrScheme.outline.withOpacity(
|
||||
kHintOpacity,
|
||||
),
|
||||
),
|
||||
hintText: widget.hintText,
|
||||
hintText: hintText,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.primary.withOpacity(
|
||||
color: clrScheme.primary.withOpacity(
|
||||
kHintOpacity,
|
||||
),
|
||||
),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: colorScheme.surfaceVariant,
|
||||
color: clrScheme.surfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged: widget.onChanged,
|
||||
onChanged: onChanged,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,14 @@ class MethodBox extends StatelessWidget {
|
||||
if (method == HTTPVerb.delete) {
|
||||
text = "DEL";
|
||||
}
|
||||
if (method == HTTPVerb.patch) {
|
||||
text = "PAT";
|
||||
}
|
||||
return SizedBox(
|
||||
width: 28,
|
||||
width: 24,
|
||||
child: Text(
|
||||
text,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
@ -1,22 +1,24 @@
|
||||
export 'editor.dart';
|
||||
export 'buttons.dart';
|
||||
export 'tables.dart';
|
||||
export 'previewer.dart';
|
||||
export 'cards.dart';
|
||||
export 'checkbox.dart';
|
||||
export 'code_previewer.dart';
|
||||
export 'codegen_previewer.dart';
|
||||
export 'error_message.dart';
|
||||
export 'dropdowns.dart';
|
||||
export 'splitviews.dart';
|
||||
export 'texts.dart';
|
||||
export 'textfields.dart';
|
||||
export 'editor.dart';
|
||||
export 'error_message.dart';
|
||||
export 'headerfield.dart';
|
||||
export 'menus.dart';
|
||||
export 'cards.dart';
|
||||
export 'intro_message.dart';
|
||||
export 'json_previewer.dart';
|
||||
export 'markdown.dart';
|
||||
export 'menus.dart';
|
||||
export 'previewer.dart';
|
||||
export 'request_widgets.dart';
|
||||
export 'response_widgets.dart';
|
||||
export 'snackbars.dart';
|
||||
export 'markdown.dart';
|
||||
export 'uint8_audio_player.dart';
|
||||
export 'splitviews.dart';
|
||||
export 'tables.dart';
|
||||
export 'tabs.dart';
|
||||
export 'json_previewer.dart';
|
||||
export 'textfields.dart';
|
||||
export 'texts.dart';
|
||||
export 'uint8_audio_player.dart';
|
||||
export 'window_caption.dart';
|
||||
|
98
lib/widgets/window_caption.dart
Normal file
98
lib/widgets/window_caption.dart
Normal file
@ -0,0 +1,98 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
const double kWindowCaptionHeight = 30;
|
||||
|
||||
class WindowCaption extends StatefulWidget {
|
||||
const WindowCaption({
|
||||
super.key,
|
||||
this.backgroundColor,
|
||||
this.brightness,
|
||||
});
|
||||
|
||||
final Color? backgroundColor;
|
||||
final Brightness? brightness;
|
||||
|
||||
@override
|
||||
State<WindowCaption> createState() => _WindowCaptionState();
|
||||
}
|
||||
|
||||
class _WindowCaptionState extends State<WindowCaption> with WindowListener {
|
||||
@override
|
||||
void initState() {
|
||||
windowManager.addListener(this);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
windowManager.removeListener(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onPanStart: (details) {
|
||||
windowManager.startDragging();
|
||||
},
|
||||
child: const SizedBox(
|
||||
height: double.infinity,
|
||||
),
|
||||
),
|
||||
),
|
||||
WindowCaptionButton.minimize(
|
||||
brightness: widget.brightness,
|
||||
onPressed: () async {
|
||||
bool isMinimized = await windowManager.isMinimized();
|
||||
if (isMinimized) {
|
||||
windowManager.restore();
|
||||
} else {
|
||||
windowManager.minimize();
|
||||
}
|
||||
},
|
||||
),
|
||||
FutureBuilder<bool>(
|
||||
future: windowManager.isMaximized(),
|
||||
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
|
||||
if (snapshot.data == true) {
|
||||
return WindowCaptionButton.unmaximize(
|
||||
brightness: widget.brightness,
|
||||
onPressed: () {
|
||||
windowManager.unmaximize();
|
||||
},
|
||||
);
|
||||
}
|
||||
return WindowCaptionButton.maximize(
|
||||
brightness: widget.brightness,
|
||||
onPressed: () {
|
||||
windowManager.maximize();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
WindowCaptionButton.close(
|
||||
brightness: widget.brightness,
|
||||
onPressed: () {
|
||||
windowManager.close();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowMaximize() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowUnmaximize() {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
267
pubspec.lock
267
pubspec.lock
@ -5,26 +5,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
||||
sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "61.0.0"
|
||||
version: "64.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
||||
sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.13.0"
|
||||
version: "6.2.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03"
|
||||
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.6"
|
||||
version: "3.4.9"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -45,10 +45,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: audio_session
|
||||
sha256: "8a2bc5e30520e18f3fb0e366793d78057fb64cd5287862c76af0c8771f2a52ad"
|
||||
sha256: "6fdf255ed3af86535c96452c33ecff1245990bb25a605bfb1958661ccc3d467f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.16"
|
||||
version: "0.1.18"
|
||||
axis_layout:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -61,10 +61,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: barcode
|
||||
sha256: "789f898eef0bd88312470bdb2cc996f895ad7dd5f89e9adde84b204546a90b45"
|
||||
sha256: "2a8b2ee065f419c2aeda141436cc556d91ae772d220fd80679f4d431d6c2ab43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
version: "2.2.5"
|
||||
bidi:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -101,26 +101,26 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65"
|
||||
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
version: "4.0.1"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8"
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
version: "2.4.2"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
|
||||
sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.6"
|
||||
version: "2.4.7"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -141,10 +141,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: a8de5955205b4d1dbbbc267daddf2178bd737e4bab8987c04a500478c9651e74
|
||||
sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.6.3"
|
||||
version: "8.8.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -165,10 +165,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
|
||||
sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
version: "0.4.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -178,21 +178,21 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "1be9be30396d7e4c0db42c35ea6ccd7cc6a1e19916b5dc64d6ac216b5544d677"
|
||||
sha256: feee43a5c05e7b3199bb375a86430b8ada1b04104f2923d0e03cc01ca87b6d84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.7.0"
|
||||
version: "4.9.0"
|
||||
collection:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.17.2"
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -205,10 +205,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: coverage
|
||||
sha256: "595a29b55ce82d53398e1bcc2cba525d7bd7c59faeb2d2540e9d42c390cfeeeb"
|
||||
sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.4"
|
||||
version: "1.7.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -218,13 +218,13 @@ packages:
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
|
||||
sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
version: "2.3.4"
|
||||
davi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -265,6 +265,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
file_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -338,26 +346,42 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: ad76540d21c066228ee3f9d1dad64a9f7e46530e8bb7c85011a88bc1fd874bc5
|
||||
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
version: "3.0.1"
|
||||
flutter_markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
sha256: "8afc9a6aa6d8e8063523192ba837149dbf3d377a37c0b0fc579149a1fbd4a619"
|
||||
sha256: "35108526a233cc0755664d445f8a6b4b61e6f8fe993b3658b80b4a26827fc196"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.18"
|
||||
version: "0.6.18+2"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.17"
|
||||
flutter_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: bdba94be666ecb1beeb0f5a748d96cdd6a37215f27e6b48c7673b95cecb800c8
|
||||
sha256: da9591d1f8d5881628ccd5c25c40e74fc3eef50ba45e40c3905a06e1712412d5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.4"
|
||||
version: "2.4.9"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.9"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -380,10 +404,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: freezed
|
||||
sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a"
|
||||
sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.5"
|
||||
version: "2.4.6"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -460,10 +484,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.2"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -523,11 +547,12 @@ packages:
|
||||
json_data_explorer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_data_explorer
|
||||
sha256: "303a00037b23963fd01be1b2dc509f14e9db2a40f852b0ce042d7635c22fd154"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
path: "."
|
||||
ref: "9fa58d7b51e65174ab11cbcae17bba88a4194dde"
|
||||
resolved-ref: "9fa58d7b51e65174ab11cbcae17bba88a4194dde"
|
||||
url: "https://github.com/foss42/json_data_explorer.git"
|
||||
source: git
|
||||
version: "0.1.2"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -540,10 +565,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: just_audio
|
||||
sha256: "5ed0cd723e17dfd8cd4b0253726221e67f6546841ea4553635cf895061fc335b"
|
||||
sha256: b607cd1a43bac03d85c3aaee00448ff4a589ef2a77104e3d409889ff079bf823
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.35"
|
||||
version: "0.9.36"
|
||||
just_audio_mpv:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -556,18 +581,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: just_audio_platform_interface
|
||||
sha256: d8409da198bbc59426cd45d4c92fca522a2ec269b576ce29459d6d6fcaeb44df
|
||||
sha256: c3dee0014248c97c91fe6299edb73dc4d6c6930a2f4f713579cd692d9e47f4a1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.1"
|
||||
version: "4.2.2"
|
||||
just_audio_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: just_audio_web
|
||||
sha256: ff62f733f437b25a0ff590f0e295fa5441dcb465f1edbdb33b3dea264705bc13
|
||||
sha256: "134356b0fe3d898293102b33b5fd618831ffdc72bb7a1b726140abdf22772b70"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.8"
|
||||
version: "0.4.9"
|
||||
just_audio_windows:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -628,10 +653,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
|
||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
version: "1.10.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -732,10 +757,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1"
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -772,18 +797,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pdf
|
||||
sha256: "9f75fc7f5580ea5e635b5724de58fb27f684c9ad03ed46fdc1aac768e4557315"
|
||||
sha256: "93cbb2c06de9bab91844550f19896b2373e7a5ce25173995e7e5ec5e1741429d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.4"
|
||||
version: "3.10.7"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.4.0"
|
||||
version: "6.0.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -796,18 +821,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
version: "2.1.7"
|
||||
pointer_interceptor:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointer_interceptor
|
||||
sha256: "7626e034489820fd599380d2bb4d3f4a0a5e3529370b62bfce53ab736b91adb2"
|
||||
sha256: adf7a637f97c077041d36801b43be08559fd4322d2127b3f20bb7be1b9eebc22
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+6"
|
||||
version: "0.9.3+7"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -828,18 +853,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: printing
|
||||
sha256: e7c383dca95ee7b88c02dc1c66638628d3dcdc2fb2cc47e7a595facd47e46b56
|
||||
sha256: ad39a42a5f83125952457dfd94f395c8cf0eb1f7759583dadb769be5c7f99d24
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.11.0"
|
||||
version: "5.11.1"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
|
||||
sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.5"
|
||||
version: "6.1.1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -868,10 +893,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: "2af3d127a6e4e34b89b8f1f018086f5ded04b8e538174f0510bba3e4c0d878b1"
|
||||
sha256: "942999ee48b899f8a46a860f1e13cee36f2f77609eb54c5b7a669bb20d550b11"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.4"
|
||||
version: "2.4.9"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -937,10 +962,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
version: "1.5.0"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -985,10 +1010,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
version: "1.11.1"
|
||||
state_notifier:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1001,10 +1026,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1033,26 +1058,26 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46"
|
||||
sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.24.3"
|
||||
version: "1.24.9"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.0"
|
||||
version: "0.6.1"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e"
|
||||
sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.3"
|
||||
version: "0.5.9"
|
||||
textwrap:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1081,74 +1106,98 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27"
|
||||
sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.14"
|
||||
version: "6.2.2"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330
|
||||
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
version: "6.2.0"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f"
|
||||
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5"
|
||||
version: "6.2.1"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e
|
||||
sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
version: "3.1.1"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88
|
||||
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.7"
|
||||
version: "3.1.0"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618"
|
||||
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.5"
|
||||
version: "2.2.0"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5"
|
||||
sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.20"
|
||||
version: "2.2.2"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069"
|
||||
sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.8"
|
||||
version: "3.1.1"
|
||||
uuid:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: uuid
|
||||
sha256: b715b8d3858b6fa9f68f87d20d98830283628014750c2b09b6f516c1da4af2a7
|
||||
sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
version: "4.2.2"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9+1"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_codec
|
||||
sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9+1"
|
||||
vector_graphics_compiler:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.9+1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1161,10 +1210,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583
|
||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.10.0"
|
||||
version: "13.0.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1177,10 +1226,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4-beta"
|
||||
version: "0.3.0"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1201,10 +1250,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3"
|
||||
sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.9"
|
||||
version: "5.1.1"
|
||||
window_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -1234,10 +1283,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: xml
|
||||
sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.0"
|
||||
version: "6.5.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1247,5 +1296,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.1.0 <4.0.0"
|
||||
flutter: ">=3.13.0"
|
||||
dart: ">=3.2.3 <4.0.0"
|
||||
flutter: ">=3.16.0"
|
||||
|
12
pubspec.yaml
12
pubspec.yaml
@ -39,12 +39,20 @@ dependencies:
|
||||
just_audio_windows: ^0.2.0
|
||||
freezed_annotation: ^2.4.1
|
||||
json_annotation: ^4.8.1
|
||||
printing: ^5.11.0
|
||||
printing: ^5.11.1
|
||||
package_info_plus: ^4.1.0
|
||||
flutter_typeahead: ^4.8.0
|
||||
provider: ^6.0.5
|
||||
json_data_explorer: ^0.1.0
|
||||
json_data_explorer:
|
||||
git:
|
||||
url: https://github.com/foss42/json_data_explorer.git
|
||||
ref: 9fa58d7b51e65174ab11cbcae17bba88a4194dde
|
||||
scrollable_positioned_list: ^0.2.3
|
||||
file_picker: ^6.1.1
|
||||
flutter_svg: ^2.0.9
|
||||
vector_graphics_compiler: ^1.1.9+1
|
||||
code_builder: ^4.9.0
|
||||
dart_style: ^2.3.4
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
239
test/codegen/codegen_test.dart
Normal file
239
test/codegen/codegen_test.dart
Normal file
@ -0,0 +1,239 @@
|
||||
import 'package:apidash/codegen/codegen.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import '../request_models.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
final codeGen = Codegen();
|
||||
|
||||
group('Test various Code generators', () {
|
||||
test('cURL', () {
|
||||
const expectedCode = r"""curl --url 'https://api.foss42.com'""";
|
||||
expect(codeGen.getCode(CodegenLanguage.curl, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('Dart Dio', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.get('https://api.foss42.com');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(CodegenLanguage.dartDio, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('Dart HTTP', () {
|
||||
const expectedCode = r"""import 'package:http/http.dart' as http;
|
||||
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com');
|
||||
|
||||
final response = await http.get(uri);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(CodegenLanguage.dartHttp, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('HAR', () {
|
||||
const expectedCode = r"""{
|
||||
"method": "GET",
|
||||
"url": "https://api.foss42.com",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"queryString": [],
|
||||
"headers": []
|
||||
}""";
|
||||
expect(codeGen.getCode(CodegenLanguage.har, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('JS Axios', () {
|
||||
const expectedCode = r"""let config = {
|
||||
url: 'https://api.foss42.com',
|
||||
method: 'get'
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(CodegenLanguage.jsAxios, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('JS Fetch', () {
|
||||
const expectedCode = r"""let url = 'https://api.foss42.com';
|
||||
|
||||
let options = {
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(CodegenLanguage.jsFetch, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('Kotlin OkHttp', () {
|
||||
const expectedCode = r"""import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
||||
fun main() {
|
||||
val client = OkHttpClient()
|
||||
|
||||
val url = "https://api.foss42.com"
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
|
||||
println(response.code)
|
||||
println(response.body?.string())
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(
|
||||
CodegenLanguage.kotlinOkHttp, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('NodeJs Axios', () {
|
||||
const expectedCode = r"""import axios from 'axios';
|
||||
|
||||
let config = {
|
||||
url: 'https://api.foss42.com',
|
||||
method: 'get'
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(
|
||||
CodegenLanguage.nodejsAxios, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('Nodejs Fetch', () {
|
||||
const expectedCode = r"""import fetch from 'node-fetch';
|
||||
|
||||
let url = 'https://api.foss42.com';
|
||||
|
||||
let options = {
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(
|
||||
CodegenLanguage.nodejsFetch, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('Python http.client', () {
|
||||
const expectedCode = r"""import http.client
|
||||
|
||||
conn = http.client.HTTPSConnection("api.foss42.com")
|
||||
conn.request("GET", "")
|
||||
|
||||
res = conn.getresponse()
|
||||
data = res.read()
|
||||
|
||||
print(data.decode("utf-8"))
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(
|
||||
CodegenLanguage.pythonHttpClient, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('Python requests', () {
|
||||
const expectedCode = r"""import requests
|
||||
|
||||
url = 'https://api.foss42.com'
|
||||
|
||||
response = requests.get(url)
|
||||
|
||||
print('Status Code:', response.status_code)
|
||||
print('Response Body:', response.text)
|
||||
""";
|
||||
expect(
|
||||
codeGen.getCode(
|
||||
CodegenLanguage.pythonRequests, requestModelGet1, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
}
|
@ -54,6 +54,37 @@ void main() {
|
||||
--header 'User-Agent: Test Agent'""";
|
||||
expect(curlCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode =
|
||||
r"""curl --url 'https://api.foss42.com/humanize/social?num=8700000&add_space=true'""";
|
||||
expect(curlCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode =
|
||||
r"""curl --url 'https://api.foss42.com/humanize/social' \
|
||||
--header 'User-Agent: Test Agent'""";
|
||||
expect(
|
||||
curlCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode =
|
||||
r"""curl --url 'https://api.foss42.com/humanize/social?num=8700000&digits=3' \
|
||||
--header 'User-Agent: Test Agent'""";
|
||||
expect(curlCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode =
|
||||
r"""curl --url 'https://api.foss42.com/humanize/social'""";
|
||||
expect(curlCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -100,6 +131,7 @@ void main() {
|
||||
expect(curlCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""curl --request PUT \
|
||||
|
568
test/codegen/dart_dio_codegen_test.dart
Normal file
568
test/codegen/dart_dio_codegen_test.dart
Normal file
@ -0,0 +1,568 @@
|
||||
import 'package:apidash/codegen/dart/dio.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../request_models.dart';
|
||||
|
||||
void main() {
|
||||
final dartDioCodeGen = DartDioCodeGen();
|
||||
|
||||
group('GET Request', () {
|
||||
test('GET 1', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.get('https://api.foss42.com');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet1, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 2', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {'code': 'US'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.foss42.com/country/data',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet2, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 3', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {'code': 'IND'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.foss42.com/country/data?code=US',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet3, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 4', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {
|
||||
'num': '8700000',
|
||||
'digits': '3',
|
||||
'system': 'SS',
|
||||
'add_space': 'true',
|
||||
'trailing_zeros': 'true',
|
||||
};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.foss42.com/humanize/social',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet4, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 5', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final headers = {'User-Agent': 'Test Agent'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.github.com/repos/foss42/apidash',
|
||||
options: Options(headers: headers),
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet5, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 6', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {'raw': 'true'};
|
||||
final headers = {'User-Agent': 'Test Agent'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.github.com/repos/foss42/apidash',
|
||||
queryParameters: queryParams,
|
||||
options: Options(headers: headers),
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet6, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 7', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.get('https://api.foss42.com');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet7, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 8', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {'raw': 'true'};
|
||||
final headers = {'User-Agent': 'Test Agent'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.github.com/repos/foss42/apidash',
|
||||
queryParameters: queryParams,
|
||||
options: Options(headers: headers),
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {
|
||||
'num': '8700000',
|
||||
'add_space': 'true',
|
||||
};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.foss42.com/humanize/social',
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final headers = {'User-Agent': 'Test Agent'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.foss42.com/humanize/social',
|
||||
options: Options(headers: headers),
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
dartDioCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final queryParams = {
|
||||
'num': '8700000',
|
||||
'digits': '3',
|
||||
};
|
||||
final headers = {'User-Agent': 'Test Agent'};
|
||||
final response = await dio.Dio.get(
|
||||
'https://api.foss42.com/humanize/social',
|
||||
queryParameters: queryParams,
|
||||
options: Options(headers: headers),
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.get('https://api.foss42.com/humanize/social');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
test('HEAD 1', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.head('https://api.foss42.com');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelHead1, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('HEAD 2', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.head('http://api.foss42.com');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelHead2, "http"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('POST Request', () {
|
||||
test('POST 1', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final data = r'''{
|
||||
"text": "I LOVE Flutter"
|
||||
}''';
|
||||
final response = await dio.Dio.post(
|
||||
'https://api.foss42.com/case/lower',
|
||||
data: data,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelPost1, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('POST 2', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
import 'dart:convert' as convert;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final data = convert.json.decode(r'''{
|
||||
"text": "I LOVE Flutter"
|
||||
}''');
|
||||
final response = await dio.Dio.post(
|
||||
'https://api.foss42.com/case/lower',
|
||||
data: data,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelPost2, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('POST 3', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
import 'dart:convert' as convert;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final headers = {'User-Agent': 'Test Agent'};
|
||||
final data = convert.json.decode(r'''{
|
||||
"text": "I LOVE Flutter"
|
||||
}''');
|
||||
final response = await dio.Dio.post(
|
||||
'https://api.foss42.com/case/lower',
|
||||
options: Options(headers: headers),
|
||||
data: data,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
import 'dart:convert' as convert;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final data = convert.json.decode(r'''{
|
||||
"name": "morpheus",
|
||||
"job": "zion resident"
|
||||
}''');
|
||||
final response = await dio.Dio.put(
|
||||
'https://reqres.in/api/users/2',
|
||||
data: data,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelPut1, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PATCH Request', () {
|
||||
test('PATCH 1', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
import 'dart:convert' as convert;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final data = convert.json.decode(r'''{
|
||||
"name": "marfeus",
|
||||
"job": "accountant"
|
||||
}''');
|
||||
final response = await dio.Dio.patch(
|
||||
'https://reqres.in/api/users/2',
|
||||
data: data,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartDioCodeGen.getCode(requestModelPatch1, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('DELETE Request', () {
|
||||
test('DELETE 1', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final response = await dio.Dio.delete('https://reqres.in/api/users/2');
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
dartDioCodeGen.getCode(requestModelDelete1, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('DELETE 2', () {
|
||||
const expectedCode = r"""import 'package:dio/dio.dart' as dio;
|
||||
import 'dart:convert' as convert;
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
final data = convert.json.decode(r'''{
|
||||
"name": "marfeus",
|
||||
"job": "accountant"
|
||||
}''');
|
||||
final response = await dio.Dio.delete(
|
||||
'https://reqres.in/api/users/2',
|
||||
data: data,
|
||||
);
|
||||
print(response.statusCode);
|
||||
print(response.data);
|
||||
} on DioException catch (e, s) {
|
||||
print(e.response?.statusCode);
|
||||
print(e.response?.data);
|
||||
print(s);
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
dartDioCodeGen.getCode(requestModelDelete2, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import 'package:apidash/codegen/dart/http.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../request_models.dart';
|
||||
|
||||
void main() {
|
||||
@ -18,8 +19,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -34,9 +34,7 @@ void main() async {
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/country/data');
|
||||
|
||||
var queryParams = {
|
||||
"code": "US"
|
||||
};
|
||||
var queryParams = {'code': 'US'};
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
|
||||
final response = await http.get(uri);
|
||||
@ -45,13 +43,13 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
expect(dartHttpCodeGen.getCode(requestModelGet2, "https"), expectedCode);
|
||||
});
|
||||
|
||||
@ -61,10 +59,8 @@ void main() async {
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/country/data?code=US');
|
||||
|
||||
var queryParams = {
|
||||
"code": "IND"
|
||||
};
|
||||
var urlQueryParams = Map<String,String>.from(uri.queryParameters);
|
||||
var queryParams = {'code': 'IND'};
|
||||
var urlQueryParams = Map<String, String>.from(uri.queryParameters);
|
||||
urlQueryParams.addAll(queryParams);
|
||||
uri = uri.replace(queryParameters: urlQueryParams);
|
||||
|
||||
@ -74,8 +70,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -91,11 +86,11 @@ void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/humanize/social');
|
||||
|
||||
var queryParams = {
|
||||
"num": "8700000",
|
||||
"digits": "3",
|
||||
"system": "SS",
|
||||
"add_space": "true",
|
||||
"trailing_zeros": "true"
|
||||
'num': '8700000',
|
||||
'digits': '3',
|
||||
'system': 'SS',
|
||||
'add_space': 'true',
|
||||
'trailing_zeros': 'true',
|
||||
};
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
|
||||
@ -105,8 +100,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -121,19 +115,18 @@ void main() async {
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.github.com/repos/foss42/apidash');
|
||||
|
||||
var headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
};
|
||||
var headers = {'User-Agent': 'Test Agent'};
|
||||
|
||||
final response = await http.get(uri,
|
||||
headers: headers);
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: headers,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -148,24 +141,21 @@ void main() async {
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.github.com/repos/foss42/apidash');
|
||||
|
||||
var queryParams = {
|
||||
"raw": "true"
|
||||
};
|
||||
var queryParams = {'raw': 'true'};
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
|
||||
var headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
};
|
||||
var headers = {'User-Agent': 'Test Agent'};
|
||||
|
||||
final response = await http.get(uri,
|
||||
headers: headers);
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: headers,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -186,8 +176,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -202,24 +191,21 @@ void main() async {
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.github.com/repos/foss42/apidash');
|
||||
|
||||
var queryParams = {
|
||||
"raw": "true"
|
||||
};
|
||||
var queryParams = {'raw': 'true'};
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
|
||||
var headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
};
|
||||
var headers = {'User-Agent': 'Test Agent'};
|
||||
|
||||
final response = await http.get(uri,
|
||||
headers: headers);
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: headers,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -227,6 +213,117 @@ void main() async {
|
||||
""";
|
||||
expect(dartHttpCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import 'package:http/http.dart' as http;
|
||||
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/humanize/social');
|
||||
|
||||
var queryParams = {
|
||||
'num': '8700000',
|
||||
'add_space': 'true',
|
||||
};
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
|
||||
final response = await http.get(uri);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartHttpCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import 'package:http/http.dart' as http;
|
||||
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/humanize/social');
|
||||
|
||||
var headers = {'User-Agent': 'Test Agent'};
|
||||
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: headers,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
dartHttpCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import 'package:http/http.dart' as http;
|
||||
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/humanize/social');
|
||||
|
||||
var queryParams = {
|
||||
'num': '8700000',
|
||||
'digits': '3',
|
||||
};
|
||||
uri = uri.replace(queryParameters: queryParams);
|
||||
|
||||
var headers = {'User-Agent': 'Test Agent'};
|
||||
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: headers,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartHttpCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import 'package:http/http.dart' as http;
|
||||
|
||||
void main() async {
|
||||
var uri = Uri.parse('https://api.foss42.com/humanize/social');
|
||||
|
||||
final response = await http.get(uri);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
}
|
||||
""";
|
||||
expect(dartHttpCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -242,8 +339,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -264,8 +360,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -286,20 +381,19 @@ void main() async {
|
||||
"text": "I LOVE Flutter"
|
||||
}''';
|
||||
|
||||
var headers = {
|
||||
"content-type": "text/plain"
|
||||
};
|
||||
var headers = {'content-type': 'text/plain'};
|
||||
|
||||
final response = await http.post(uri,
|
||||
final response = await http.post(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body);
|
||||
body: body,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -318,20 +412,19 @@ void main() async {
|
||||
"text": "I LOVE Flutter"
|
||||
}''';
|
||||
|
||||
var headers = {
|
||||
"content-type": "application/json"
|
||||
};
|
||||
var headers = {'content-type': 'application/json'};
|
||||
|
||||
final response = await http.post(uri,
|
||||
final response = await http.post(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body);
|
||||
body: body,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -351,20 +444,21 @@ void main() async {
|
||||
}''';
|
||||
|
||||
var headers = {
|
||||
"User-Agent": "Test Agent",
|
||||
"content-type": "application/json"
|
||||
'User-Agent': 'Test Agent',
|
||||
'content-type': 'application/json',
|
||||
};
|
||||
|
||||
final response = await http.post(uri,
|
||||
final response = await http.post(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body);
|
||||
body: body,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -373,6 +467,7 @@ void main() async {
|
||||
expect(dartHttpCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""import 'package:http/http.dart' as http;
|
||||
@ -385,20 +480,19 @@ void main() async {
|
||||
"job": "zion resident"
|
||||
}''';
|
||||
|
||||
var headers = {
|
||||
"content-type": "application/json"
|
||||
};
|
||||
var headers = {'content-type': 'application/json'};
|
||||
|
||||
final response = await http.put(uri,
|
||||
final response = await http.put(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body);
|
||||
body: body,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -420,20 +514,19 @@ void main() async {
|
||||
"job": "accountant"
|
||||
}''';
|
||||
|
||||
var headers = {
|
||||
"content-type": "application/json"
|
||||
};
|
||||
var headers = {'content-type': 'application/json'};
|
||||
|
||||
final response = await http.patch(uri,
|
||||
final response = await http.patch(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body);
|
||||
body: body,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -457,8 +550,7 @@ void main() async {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
@ -479,20 +571,19 @@ void main() async {
|
||||
"job": "accountant"
|
||||
}''';
|
||||
|
||||
var headers = {
|
||||
"content-type": "application/json"
|
||||
};
|
||||
var headers = {'content-type': 'application/json'};
|
||||
|
||||
final response = await http.delete(uri,
|
||||
final response = await http.delete(
|
||||
uri,
|
||||
headers: headers,
|
||||
body: body);
|
||||
body: body,
|
||||
);
|
||||
|
||||
int statusCode = response.statusCode;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
print('Status Code: $statusCode');
|
||||
print('Response Body: ${response.body}');
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
print('Error Status Code: $statusCode');
|
||||
print('Error Response Body: ${response.body}');
|
||||
}
|
||||
|
@ -149,6 +149,83 @@ void main() {
|
||||
}""";
|
||||
expect(harCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""{
|
||||
"method": "GET",
|
||||
"url": "https://api.foss42.com/humanize/social?num=8700000&add_space=true",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"queryString": [
|
||||
{
|
||||
"name": "num",
|
||||
"value": "8700000"
|
||||
},
|
||||
{
|
||||
"name": "add_space",
|
||||
"value": "true"
|
||||
}
|
||||
],
|
||||
"headers": []
|
||||
}""";
|
||||
expect(harCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""{
|
||||
"method": "GET",
|
||||
"url": "https://api.foss42.com/humanize/social",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"queryString": [],
|
||||
"headers": [
|
||||
{
|
||||
"name": "User-Agent",
|
||||
"value": "Test Agent"
|
||||
}
|
||||
]
|
||||
}""";
|
||||
expect(
|
||||
harCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""{
|
||||
"method": "GET",
|
||||
"url": "https://api.foss42.com/humanize/social?num=8700000&digits=3",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"queryString": [
|
||||
{
|
||||
"name": "num",
|
||||
"value": "8700000"
|
||||
},
|
||||
{
|
||||
"name": "digits",
|
||||
"value": "3"
|
||||
}
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"name": "User-Agent",
|
||||
"value": "Test Agent"
|
||||
}
|
||||
]
|
||||
}""";
|
||||
expect(harCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""{
|
||||
"method": "GET",
|
||||
"url": "https://api.foss42.com/humanize/social",
|
||||
"httpVersion": "HTTP/1.1",
|
||||
"queryString": [],
|
||||
"headers": []
|
||||
}""";
|
||||
expect(harCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -240,6 +317,7 @@ void main() {
|
||||
expect(harCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""{
|
||||
|
@ -201,6 +201,109 @@ axios(config)
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get',
|
||||
params: {
|
||||
"num": "8700000",
|
||||
"add_space": "true"
|
||||
}
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get',
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
axiosCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get',
|
||||
params: {
|
||||
"num": "8700000",
|
||||
"digits": "3"
|
||||
},
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get'
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -324,6 +427,7 @@ axios(config)
|
||||
expect(axiosCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""let config = {
|
||||
|
@ -220,6 +220,121 @@ fetch(url, options)
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode =
|
||||
r"""let url = 'https://api.foss42.com/humanize/social?num=8700000&add_space=true';
|
||||
|
||||
let options = {
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode =
|
||||
r"""let url = 'https://api.foss42.com/humanize/social';
|
||||
|
||||
let options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
fetchCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode =
|
||||
r"""let url = 'https://api.foss42.com/humanize/social?num=8700000&digits=3';
|
||||
|
||||
let options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode =
|
||||
r"""let url = 'https://api.foss42.com/humanize/social';
|
||||
|
||||
let options = {
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -366,6 +481,7 @@ fetch(url, options)
|
||||
expect(fetchCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""let url = 'https://reqres.in/api/users/2';
|
||||
|
@ -219,6 +219,116 @@ fun main() {
|
||||
expect(
|
||||
kotlinOkHttpCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
|
||||
fun main() {
|
||||
val client = OkHttpClient()
|
||||
|
||||
val url = "https://api.foss42.com/humanize/social".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("num", "8700000")
|
||||
.addQueryParameter("add_space", "true")
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
|
||||
println(response.code)
|
||||
println(response.body?.string())
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
kotlinOkHttpCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
||||
fun main() {
|
||||
val client = OkHttpClient()
|
||||
|
||||
val url = "https://api.foss42.com/humanize/social"
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("User-Agent", "Test Agent")
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
|
||||
println(response.code)
|
||||
println(response.body?.string())
|
||||
}
|
||||
""";
|
||||
expect(
|
||||
kotlinOkHttpCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
|
||||
fun main() {
|
||||
val client = OkHttpClient()
|
||||
|
||||
val url = "https://api.foss42.com/humanize/social".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("num", "8700000")
|
||||
.addQueryParameter("digits", "3")
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("User-Agent", "Test Agent")
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
|
||||
println(response.code)
|
||||
println(response.body?.string())
|
||||
}
|
||||
""";
|
||||
expect(kotlinOkHttpCodeGen.getCode(requestModelGet11, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
||||
fun main() {
|
||||
val client = OkHttpClient()
|
||||
|
||||
val url = "https://api.foss42.com/humanize/social"
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val response = client.newCall(request).execute()
|
||||
|
||||
println(response.code)
|
||||
println(response.body?.string())
|
||||
}
|
||||
""";
|
||||
expect(kotlinOkHttpCodeGen.getCode(requestModelGet12, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -369,6 +479,7 @@ fun main() {
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r'''import okhttp3.OkHttpClient
|
||||
|
@ -217,6 +217,117 @@ axios(config)
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import axios from 'axios';
|
||||
|
||||
let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get',
|
||||
params: {
|
||||
"num": "8700000",
|
||||
"add_space": "true"
|
||||
}
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import axios from 'axios';
|
||||
|
||||
let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get',
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
axiosCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import axios from 'axios';
|
||||
|
||||
let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get',
|
||||
params: {
|
||||
"num": "8700000",
|
||||
"digits": "3"
|
||||
},
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import axios from 'axios';
|
||||
|
||||
let config = {
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: 'get'
|
||||
};
|
||||
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
// handle success
|
||||
console.log(response.status);
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
// handle error
|
||||
console.log(error.response.status);
|
||||
console.log(error);
|
||||
});
|
||||
""";
|
||||
expect(axiosCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -350,6 +461,7 @@ axios(config)
|
||||
expect(axiosCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""import axios from 'axios';
|
||||
|
@ -230,6 +230,125 @@ fetch(url, options)
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet8, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import fetch from 'node-fetch';
|
||||
|
||||
let url = 'https://api.foss42.com/humanize/social?num=8700000&add_space=true';
|
||||
|
||||
let options = {
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet9, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import fetch from 'node-fetch';
|
||||
|
||||
let url = 'https://api.foss42.com/humanize/social';
|
||||
|
||||
let options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(
|
||||
fetchCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import fetch from 'node-fetch';
|
||||
|
||||
let url = 'https://api.foss42.com/humanize/social?num=8700000&digits=3';
|
||||
|
||||
let options = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet11, "https"), expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import fetch from 'node-fetch';
|
||||
|
||||
let url = 'https://api.foss42.com/humanize/social';
|
||||
|
||||
let options = {
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
let status;
|
||||
fetch(url, options)
|
||||
.then(res => {
|
||||
status = res.status;
|
||||
return res.json()
|
||||
})
|
||||
.then(body => {
|
||||
console.log(status);
|
||||
console.log(body);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(status);
|
||||
console.error('error:' + err);
|
||||
});
|
||||
""";
|
||||
expect(fetchCodeGen.getCode(requestModelGet12, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -386,6 +505,7 @@ fetch(url, options)
|
||||
expect(fetchCodeGen.getCode(requestModelPost3, "https"), expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""import fetch from 'node-fetch';
|
||||
|
@ -174,6 +174,94 @@ print(data.decode("utf-8"))
|
||||
expect(pythonHttpClientCodeGen.getCode(requestModelGet8, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import http.client
|
||||
from urllib.parse import urlencode
|
||||
|
||||
queryParams = {
|
||||
"num": "8700000",
|
||||
"add_space": "true"
|
||||
}
|
||||
queryParamsStr = '?' + urlencode(queryParams)
|
||||
|
||||
conn = http.client.HTTPSConnection("api.foss42.com")
|
||||
conn.request("GET", "/humanize/social" + queryParamsStr)
|
||||
|
||||
res = conn.getresponse()
|
||||
data = res.read()
|
||||
|
||||
print(data.decode("utf-8"))
|
||||
""";
|
||||
expect(pythonHttpClientCodeGen.getCode(requestModelGet9, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import http.client
|
||||
|
||||
headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
|
||||
conn = http.client.HTTPSConnection("api.foss42.com")
|
||||
conn.request("GET", "/humanize/social",
|
||||
headers= headers)
|
||||
|
||||
res = conn.getresponse()
|
||||
data = res.read()
|
||||
|
||||
print(data.decode("utf-8"))
|
||||
""";
|
||||
expect(
|
||||
pythonHttpClientCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import http.client
|
||||
from urllib.parse import urlencode
|
||||
|
||||
queryParams = {
|
||||
"num": "8700000",
|
||||
"digits": "3"
|
||||
}
|
||||
queryParamsStr = '?' + urlencode(queryParams)
|
||||
|
||||
headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
|
||||
conn = http.client.HTTPSConnection("api.foss42.com")
|
||||
conn.request("GET", "/humanize/social" + queryParamsStr,
|
||||
headers= headers)
|
||||
|
||||
res = conn.getresponse()
|
||||
data = res.read()
|
||||
|
||||
print(data.decode("utf-8"))
|
||||
""";
|
||||
expect(pythonHttpClientCodeGen.getCode(requestModelGet11, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import http.client
|
||||
|
||||
conn = http.client.HTTPSConnection("api.foss42.com")
|
||||
conn.request("GET", "/humanize/social")
|
||||
|
||||
res = conn.getresponse()
|
||||
data = res.read()
|
||||
|
||||
print(data.decode("utf-8"))
|
||||
""";
|
||||
expect(pythonHttpClientCodeGen.getCode(requestModelGet12, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -285,6 +373,7 @@ print(data.decode("utf-8"))
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""import http.client
|
||||
|
@ -153,6 +153,84 @@ print('Response Body:', response.text)
|
||||
expect(pythonRequestsCodeGen.getCode(requestModelGet8, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 9', () {
|
||||
const expectedCode = r"""import requests
|
||||
|
||||
url = 'https://api.foss42.com/humanize/social'
|
||||
|
||||
params = {
|
||||
"num": "8700000",
|
||||
"add_space": "true"
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
|
||||
print('Status Code:', response.status_code)
|
||||
print('Response Body:', response.text)
|
||||
""";
|
||||
expect(pythonRequestsCodeGen.getCode(requestModelGet9, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 10', () {
|
||||
const expectedCode = r"""import requests
|
||||
|
||||
url = 'https://api.foss42.com/humanize/social'
|
||||
|
||||
headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
|
||||
response = requests.get(url, headers=headers)
|
||||
|
||||
print('Status Code:', response.status_code)
|
||||
print('Response Body:', response.text)
|
||||
""";
|
||||
expect(
|
||||
pythonRequestsCodeGen.getCode(
|
||||
requestModelGet10,
|
||||
"https",
|
||||
),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 11', () {
|
||||
const expectedCode = r"""import requests
|
||||
|
||||
url = 'https://api.foss42.com/humanize/social'
|
||||
|
||||
params = {
|
||||
"num": "8700000",
|
||||
"digits": "3"
|
||||
}
|
||||
|
||||
headers = {
|
||||
"User-Agent": "Test Agent"
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params, headers=headers)
|
||||
|
||||
print('Status Code:', response.status_code)
|
||||
print('Response Body:', response.text)
|
||||
""";
|
||||
expect(pythonRequestsCodeGen.getCode(requestModelGet11, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
|
||||
test('GET 12', () {
|
||||
const expectedCode = r"""import requests
|
||||
|
||||
url = 'https://api.foss42.com/humanize/social'
|
||||
|
||||
response = requests.get(url)
|
||||
|
||||
print('Status Code:', response.status_code)
|
||||
print('Response Body:', response.text)
|
||||
""";
|
||||
expect(pythonRequestsCodeGen.getCode(requestModelGet12, "https"),
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('HEAD Request', () {
|
||||
@ -248,6 +326,7 @@ print('Response Body:', response.text)
|
||||
expectedCode);
|
||||
});
|
||||
});
|
||||
|
||||
group('PUT Request', () {
|
||||
test('PUT 1', () {
|
||||
const expectedCode = r"""import requests
|
||||
|
44
test/models/form_data_model_test.dart
Normal file
44
test/models/form_data_model_test.dart
Normal file
@ -0,0 +1,44 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:apidash/models/form_data_model.dart';
|
||||
|
||||
void main() {
|
||||
const fdmRow1 = FormDataModel(
|
||||
name: "harry",
|
||||
value: "23",
|
||||
type: FormDataType.text,
|
||||
);
|
||||
|
||||
test('Testing toString()', () {
|
||||
const resultExpected =
|
||||
'FormDataModel(name: harry, value: 23, type: FormDataType.text)';
|
||||
expect(fdmRow1.toString(), resultExpected);
|
||||
});
|
||||
|
||||
test('Testing toJson()', () {
|
||||
const resultExpected = {"name": "harry", "value": "23", "type": "text"};
|
||||
expect(fdmRow1.toJson(), resultExpected);
|
||||
});
|
||||
test('Testing fromJson()', () {
|
||||
const resultExpected = fdmRow1;
|
||||
expect(
|
||||
FormDataModel.fromJson(
|
||||
{"name": "harry", "value": "23", "type": "text"}),
|
||||
resultExpected);
|
||||
});
|
||||
|
||||
test('Testing copyWith()', () {
|
||||
const resultExpected = FormDataModel(
|
||||
name: "winter",
|
||||
value: "26",
|
||||
type: FormDataType.file,
|
||||
);
|
||||
expect(
|
||||
fdmRow1.copyWith(name: "winter", value: "26", type: FormDataType.file),
|
||||
resultExpected);
|
||||
});
|
||||
|
||||
test('Testing hashcode', () {
|
||||
expect(fdmRow1.hashCode, greaterThan(0));
|
||||
});
|
||||
}
|
@ -13,6 +13,11 @@ void main() {
|
||||
const resultExpected = {"name": "harry", "value": 23};
|
||||
expect(nmRow1.toJson(), resultExpected);
|
||||
});
|
||||
test('Testing fromJson()', () {
|
||||
const resultExpected = nmRow1;
|
||||
expect(NameValueModel.fromJson({"name": "harry", "value": 23}),
|
||||
resultExpected);
|
||||
});
|
||||
|
||||
test('Testing copyWith()', () {
|
||||
const resultExpected = NameValueModel(name: "winter", value: "26");
|
||||
|
@ -106,11 +106,14 @@ void main() {
|
||||
'content-length': '18',
|
||||
'content-type': 'application/json; charset=utf-8'
|
||||
},
|
||||
'isHeaderEnabledList': null,
|
||||
'requestParams': null,
|
||||
'isParamEnabledList': null,
|
||||
"requestBodyContentType": 'json',
|
||||
"requestBody": '''{
|
||||
"text":"WORLD"
|
||||
}''',
|
||||
'requestFormDataList': null,
|
||||
'responseStatus': null,
|
||||
'message': null,
|
||||
'responseModel': null
|
||||
@ -140,9 +143,12 @@ void main() {
|
||||
"Request Description: ",
|
||||
"Request Tab Index: 0",
|
||||
"Request Headers: [NameValueModel(name: content-length, value: 18), NameValueModel(name: content-type, value: application/json; charset=utf-8)]",
|
||||
"Enabled Headers: null",
|
||||
"Request Params: null",
|
||||
"Enabled Params: null",
|
||||
"Request Body Content Type: ContentType.json",
|
||||
'Request Body: {\n"text":"WORLD"\n}',
|
||||
'Request FormData: null',
|
||||
"Response Status: null",
|
||||
"Response Message: null",
|
||||
"Response: null"
|
||||
@ -150,6 +156,29 @@ void main() {
|
||||
test('Testing toString', () {
|
||||
expect(requestModelDup.toString(), requestModeDupString);
|
||||
});
|
||||
|
||||
test('Testing getters', () {
|
||||
expect(requestModel.enabledRequestHeaders, const [
|
||||
NameValueModel(name: 'content-length', value: '18'),
|
||||
NameValueModel(
|
||||
name: 'content-type', value: 'application/json; charset=utf-8')
|
||||
]);
|
||||
expect(requestModel.enabledRequestParams, null);
|
||||
expect(requestModel.enabledHeadersMap, {
|
||||
'content-length': '18',
|
||||
'content-type': 'application/json; charset=utf-8'
|
||||
});
|
||||
expect(requestModel.enabledParamsMap, {});
|
||||
expect(requestModel.headersMap, {
|
||||
'content-length': '18',
|
||||
'content-type': 'application/json; charset=utf-8'
|
||||
});
|
||||
expect(requestModel.paramsMap, {});
|
||||
expect(requestModel.formDataMapList, []);
|
||||
expect(requestModel.isFormDataRequest, false);
|
||||
expect(requestModel.hasContentTypeHeader, true);
|
||||
});
|
||||
|
||||
test('Testing hashcode', () {
|
||||
expect(requestModel.hashCode, greaterThan(0));
|
||||
});
|
||||
|
74
test/models/settings_model_test.dart
Normal file
74
test/models/settings_model_test.dart
Normal file
@ -0,0 +1,74 @@
|
||||
import 'package:test/test.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/models/settings_model.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
void main() {
|
||||
const sm = SettingsModel(
|
||||
isDark: false,
|
||||
alwaysShowCollectionPaneScrollbar: true,
|
||||
size: Size(300, 200),
|
||||
offset: Offset(100, 150),
|
||||
defaultUriScheme: "http",
|
||||
defaultCodeGenLang: CodegenLanguage.curl,
|
||||
saveResponses: true,
|
||||
);
|
||||
|
||||
test('Testing toJson()', () {
|
||||
const expectedResult = {
|
||||
"isDark": false,
|
||||
"alwaysShowCollectionPaneScrollbar": true,
|
||||
"width": 300.0,
|
||||
"height": 200.0,
|
||||
"dx": 100.0,
|
||||
"dy": 150.0,
|
||||
"defaultUriScheme": "http",
|
||||
"defaultCodeGenLang": "curl",
|
||||
"saveResponses": true,
|
||||
};
|
||||
expect(sm.toJson(), expectedResult);
|
||||
});
|
||||
|
||||
test('Testing fromJson()', () {
|
||||
const input = {
|
||||
"isDark": false,
|
||||
"alwaysShowCollectionPaneScrollbar": true,
|
||||
"width": 300.0,
|
||||
"height": 200.0,
|
||||
"dx": 100.0,
|
||||
"dy": 150.0,
|
||||
"defaultUriScheme": "http",
|
||||
"defaultCodeGenLang": "curl",
|
||||
"saveResponses": true,
|
||||
};
|
||||
expect(SettingsModel.fromJson(input), sm);
|
||||
});
|
||||
|
||||
test('Testing copyWith()', () {
|
||||
const expectedResult = SettingsModel(
|
||||
isDark: true,
|
||||
alwaysShowCollectionPaneScrollbar: true,
|
||||
size: Size(300, 200),
|
||||
offset: Offset(100, 150),
|
||||
defaultUriScheme: "http",
|
||||
defaultCodeGenLang: CodegenLanguage.curl,
|
||||
saveResponses: false,
|
||||
);
|
||||
expect(
|
||||
sm.copyWith(
|
||||
isDark: true,
|
||||
saveResponses: false,
|
||||
),
|
||||
expectedResult);
|
||||
});
|
||||
|
||||
test('Testing toString()', () {
|
||||
const expectedResult =
|
||||
"{isDark: false, alwaysShowCollectionPaneScrollbar: true, width: 300.0, height: 200.0, dx: 100.0, dy: 150.0, defaultUriScheme: http, defaultCodeGenLang: curl, saveResponses: true}";
|
||||
expect(sm.toString(), expectedResult);
|
||||
});
|
||||
|
||||
test('Testing hashcode', () {
|
||||
expect(sm.hashCode, greaterThan(0));
|
||||
});
|
||||
}
|
@ -90,6 +90,94 @@ const requestModelGet8 = RequestModel(
|
||||
],
|
||||
);
|
||||
|
||||
/// GET request model with some params enabled
|
||||
const requestModelGet9 = RequestModel(
|
||||
id: 'enabledParams',
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: HTTPVerb.get,
|
||||
requestParams: [
|
||||
NameValueModel(name: 'num', value: '8700000'),
|
||||
NameValueModel(name: 'digits', value: '3'),
|
||||
NameValueModel(name: 'system', value: 'SS'),
|
||||
NameValueModel(name: 'add_space', value: 'true'),
|
||||
],
|
||||
isParamEnabledList: [
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
],
|
||||
);
|
||||
|
||||
/// GET Request model with some headers enabled
|
||||
const requestModelGet10 = RequestModel(
|
||||
id: 'enabledParams',
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: HTTPVerb.get,
|
||||
requestHeaders: [
|
||||
NameValueModel(name: 'User-Agent', value: 'Test Agent'),
|
||||
NameValueModel(name: 'Content-Type', value: 'application/json'),
|
||||
],
|
||||
isHeaderEnabledList: [
|
||||
true,
|
||||
false,
|
||||
],
|
||||
);
|
||||
|
||||
/// GET Request model with some headers & URL parameters enabled
|
||||
const requestModelGet11 = RequestModel(
|
||||
id: 'enabledRows',
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: HTTPVerb.get,
|
||||
requestParams: [
|
||||
NameValueModel(name: 'num', value: '8700000'),
|
||||
NameValueModel(name: 'digits', value: '3'),
|
||||
NameValueModel(name: 'system', value: 'SS'),
|
||||
NameValueModel(name: 'add_space', value: 'true'),
|
||||
],
|
||||
requestHeaders: [
|
||||
NameValueModel(name: 'User-Agent', value: 'Test Agent'),
|
||||
NameValueModel(name: 'Content-Type', value: 'application/json'),
|
||||
],
|
||||
isParamEnabledList: [
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
isHeaderEnabledList: [
|
||||
true,
|
||||
false,
|
||||
],
|
||||
);
|
||||
|
||||
/// Request model with all headers & URL parameters disabled
|
||||
const requestModelGet12 = RequestModel(
|
||||
id: 'disabledRows',
|
||||
url: 'https://api.foss42.com/humanize/social',
|
||||
method: HTTPVerb.get,
|
||||
requestParams: [
|
||||
NameValueModel(name: 'num', value: '8700000'),
|
||||
NameValueModel(name: 'digits', value: '3'),
|
||||
NameValueModel(name: 'system', value: 'SS'),
|
||||
NameValueModel(name: 'add_space', value: 'true'),
|
||||
],
|
||||
requestHeaders: [
|
||||
NameValueModel(name: 'User-Agent', value: 'Test Agent'),
|
||||
NameValueModel(name: 'Content-Type', value: 'application/json'),
|
||||
],
|
||||
isParamEnabledList: [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
],
|
||||
isHeaderEnabledList: [
|
||||
false,
|
||||
false,
|
||||
],
|
||||
);
|
||||
|
||||
/// Basic HEAD request model
|
||||
const requestModelHead1 = RequestModel(
|
||||
id: 'head1',
|
||||
|
@ -1,6 +1,8 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:apidash/utils/convert_utils.dart';
|
||||
import 'package:apidash/models/name_value_model.dart';
|
||||
import 'package:apidash/models/form_data_model.dart';
|
||||
|
||||
void main() {
|
||||
group("Testing humanizeDuration function", () {
|
||||
@ -106,6 +108,92 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group("Testing rowsToFormDataMapList", () {
|
||||
test('Testing for null', () {
|
||||
expect(rowsToFormDataMapList(null), null);
|
||||
});
|
||||
test('Testing with a map value', () {
|
||||
const input = <FormDataModel>[
|
||||
FormDataModel(name: "text", value: "abc", type: FormDataType.file),
|
||||
FormDataModel(name: "lang", value: "eng", type: FormDataType.file),
|
||||
FormDataModel(name: "code", value: "1", type: FormDataType.text)
|
||||
];
|
||||
const expectedResult = [
|
||||
{"name": "text", "value": "abc", "type": "file"},
|
||||
{"name": "lang", "value": "eng", "type": "file"},
|
||||
{"name": "code", "value": "1", "type": "text"}
|
||||
];
|
||||
expect(rowsToFormDataMapList(input), expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
group("Testing mapListToFormDataModelRows", () {
|
||||
test('Testing for null', () {
|
||||
expect(mapListToFormDataModelRows(null), null);
|
||||
});
|
||||
test('Testing with a map value', () {
|
||||
const input = [
|
||||
{"name": "text", "value": "abc", "type": "file"},
|
||||
{"name": "lang", "value": "eng", "type": "file"},
|
||||
{"name": "code", "value": "1", "type": "text"}
|
||||
];
|
||||
const expectedResult = <FormDataModel>[
|
||||
FormDataModel(name: "text", value: "abc", type: FormDataType.file),
|
||||
FormDataModel(name: "lang", value: "eng", type: FormDataType.file),
|
||||
FormDataModel(name: "code", value: "1", type: FormDataType.text)
|
||||
];
|
||||
expect(mapListToFormDataModelRows(input), expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
group("Testing getFormDataType", () {
|
||||
test('Testing for null', () {
|
||||
expect(getFormDataType(null), FormDataType.text);
|
||||
});
|
||||
test('Testing with a map value', () {
|
||||
const input = "file";
|
||||
const expectedResult = FormDataType.file;
|
||||
expect(getFormDataType(input), expectedResult);
|
||||
});
|
||||
});
|
||||
|
||||
group("Testing jsonMapToBytes", () {
|
||||
test('Testing for null', () {
|
||||
expect(jsonMapToBytes(null), []);
|
||||
});
|
||||
test('Testing with a map value', () {
|
||||
Map<String, String> value1 = {"a": "1"};
|
||||
const result1Expected = [
|
||||
123,
|
||||
10,
|
||||
32,
|
||||
32,
|
||||
34,
|
||||
97,
|
||||
34,
|
||||
58,
|
||||
32,
|
||||
34,
|
||||
49,
|
||||
34,
|
||||
10,
|
||||
125
|
||||
];
|
||||
expect(jsonMapToBytes(value1), result1Expected);
|
||||
});
|
||||
});
|
||||
|
||||
group("Testing stringToBytes", () {
|
||||
test('Testing for null', () {
|
||||
expect(stringToBytes(null), null);
|
||||
});
|
||||
test('Testing with a stringToBytes value', () {
|
||||
String value1 = "ab";
|
||||
const result1Expected = [97, 98];
|
||||
expect(stringToBytes(value1), result1Expected);
|
||||
});
|
||||
});
|
||||
|
||||
group("Testing padMultilineString", () {
|
||||
String text1 =
|
||||
'''Using API Dash, you can draft API requests via an easy to use GUI which allows you to:
|
||||
@ -127,4 +215,39 @@ Easily manipulate and play around with request inputs like headers, query parame
|
||||
expect(padMultilineString(text1, 10), text1FirstLineNotPaddedExpected);
|
||||
});
|
||||
});
|
||||
|
||||
group("Test getEnabledRows", () {
|
||||
test('Testing for null', () {
|
||||
expect(getEnabledRows(null, null), null);
|
||||
});
|
||||
test('Testing for empty list', () {
|
||||
expect(getEnabledRows([], []), []);
|
||||
});
|
||||
const kvRow1 = NameValueModel(name: "code", value: "IN");
|
||||
const kvRow2 = NameValueModel(name: "lang", value: "eng");
|
||||
const kvRow3 = NameValueModel(name: "version", value: 0.1);
|
||||
const kvRow4 = NameValueModel(name: "month", value: 4);
|
||||
test('Testing with isRowEnabledList null', () {
|
||||
expect(getEnabledRows([kvRow1, kvRow2, kvRow3, kvRow4], null),
|
||||
[kvRow1, kvRow2, kvRow3, kvRow4]);
|
||||
});
|
||||
test('Testing for list with all enabled', () {
|
||||
expect(
|
||||
getEnabledRows(
|
||||
[kvRow1, kvRow2, kvRow3, kvRow4], [true, true, true, true]),
|
||||
[kvRow1, kvRow2, kvRow3, kvRow4]);
|
||||
});
|
||||
test('Testing for list with all disabled', () {
|
||||
expect(
|
||||
getEnabledRows(
|
||||
[kvRow1, kvRow2, kvRow3, kvRow4], [false, false, false, false]),
|
||||
[]);
|
||||
});
|
||||
test('Testing for list with some disabled', () {
|
||||
expect(
|
||||
getEnabledRows(
|
||||
[kvRow1, kvRow2, kvRow3, kvRow4], [true, false, true, false]),
|
||||
[kvRow1, kvRow3]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -3,15 +3,21 @@ import 'package:apidash/utils/file_utils.dart';
|
||||
|
||||
void main() {
|
||||
group(
|
||||
"Testing x function",
|
||||
"Testing File Utils",
|
||||
() {
|
||||
/*test('Test case 2', () {
|
||||
expect(showButtonLabelsInViewCodePane(350), false);
|
||||
test('Test getFileExtension', () {
|
||||
String mimetype = "text/csv";
|
||||
expect(getFileExtension(mimetype), "csv");
|
||||
});
|
||||
|
||||
test('Test case 3', () {
|
||||
expect(showButtonLabelsInViewCodePane(450), true);
|
||||
});*/
|
||||
test('Test getShortPath', () {
|
||||
String path = "A/B/C/D.csv";
|
||||
expect(getShortPath(path), ".../C/D.csv");
|
||||
});
|
||||
|
||||
test('Test getTempFileName', () {
|
||||
expect(getTempFileName().length, greaterThan(0));
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
323
test/utils/har_utils_test.dart
Normal file
323
test/utils/har_utils_test.dart
Normal file
@ -0,0 +1,323 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/utils/har_utils.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import '../request_models.dart';
|
||||
|
||||
void main() {
|
||||
group(
|
||||
"Testing HAR Utils",
|
||||
() {
|
||||
test('Test collectionToHAR', () async {
|
||||
Map<String, dynamic> expectedResult = {
|
||||
'log': {
|
||||
'creator': {
|
||||
'comment':
|
||||
'For support, check out API Dash repo - https://github.com/foss42/apidash',
|
||||
'version': '1.0',
|
||||
'name': 'API Dash'
|
||||
},
|
||||
'entries': [
|
||||
{
|
||||
'startedDateTime': 'ABC',
|
||||
'comment': 'id:get6',
|
||||
'serverIPAddress': '',
|
||||
'time': 0,
|
||||
'timings': {
|
||||
'connect': -1,
|
||||
'comment': '',
|
||||
'blocked': -1,
|
||||
'dns': -1,
|
||||
'receive': 0,
|
||||
'send': 0,
|
||||
'wait': 0,
|
||||
'ssl': -1
|
||||
},
|
||||
'response': {
|
||||
'status': 200,
|
||||
'statusText': 'OK',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'cookies': [],
|
||||
'headers': [],
|
||||
'content': {
|
||||
'size': 0,
|
||||
'mimeType': '',
|
||||
'comment': '',
|
||||
'text': ''
|
||||
},
|
||||
'redirectURL': '',
|
||||
'headersSize': 0,
|
||||
'bodySize': 0,
|
||||
'comment': ''
|
||||
},
|
||||
'request': {
|
||||
'method': 'GET',
|
||||
'url': 'https://api.github.com/repos/foss42/apidash?raw=true',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [
|
||||
{'name': 'raw', 'value': 'true', 'comment': ''}
|
||||
],
|
||||
'headers': [
|
||||
{'name': 'User-Agent', 'value': 'Test Agent', 'comment': ''}
|
||||
],
|
||||
'comment': '',
|
||||
'cookies': [],
|
||||
'headersSize': -1,
|
||||
'bodySize': 0
|
||||
},
|
||||
'cache': {}
|
||||
},
|
||||
{
|
||||
'startedDateTime': 'ABC',
|
||||
'comment': 'id:enabledRows',
|
||||
'serverIPAddress': '',
|
||||
'time': 0,
|
||||
'timings': {
|
||||
'connect': -1,
|
||||
'comment': '',
|
||||
'blocked': -1,
|
||||
'dns': -1,
|
||||
'receive': 0,
|
||||
'send': 0,
|
||||
'wait': 0,
|
||||
'ssl': -1
|
||||
},
|
||||
'response': {
|
||||
'status': 200,
|
||||
'statusText': 'OK',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'cookies': [],
|
||||
'headers': [],
|
||||
'content': {
|
||||
'size': 0,
|
||||
'mimeType': '',
|
||||
'comment': '',
|
||||
'text': ''
|
||||
},
|
||||
'redirectURL': '',
|
||||
'headersSize': 0,
|
||||
'bodySize': 0,
|
||||
'comment': ''
|
||||
},
|
||||
'request': {
|
||||
'method': 'GET',
|
||||
'url':
|
||||
'https://api.foss42.com/humanize/social?num=8700000&digits=3&system=SS&add_space=true',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [
|
||||
{'name': 'num', 'value': '8700000', 'comment': ''},
|
||||
{'name': 'digits', 'value': '3', 'comment': ''},
|
||||
{'name': 'system', 'value': 'SS', 'comment': ''},
|
||||
{'name': 'add_space', 'value': 'true', 'comment': ''}
|
||||
],
|
||||
'headers': [
|
||||
{
|
||||
'name': 'User-Agent',
|
||||
'value': 'Test Agent',
|
||||
'comment': ''
|
||||
},
|
||||
{
|
||||
'name': 'Content-Type',
|
||||
'value': 'application/json',
|
||||
'comment': ''
|
||||
}
|
||||
],
|
||||
'comment': '',
|
||||
'cookies': [],
|
||||
'headersSize': -1,
|
||||
'bodySize': 0
|
||||
},
|
||||
'cache': {}
|
||||
},
|
||||
{
|
||||
'startedDateTime': 'ABC',
|
||||
'comment': 'id:post3',
|
||||
'serverIPAddress': '',
|
||||
'time': 0,
|
||||
'timings': {
|
||||
'connect': -1,
|
||||
'comment': '',
|
||||
'blocked': -1,
|
||||
'dns': -1,
|
||||
'receive': 0,
|
||||
'send': 0,
|
||||
'wait': 0,
|
||||
'ssl': -1
|
||||
},
|
||||
'response': {
|
||||
'status': 200,
|
||||
'statusText': 'OK',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'cookies': [],
|
||||
'headers': [],
|
||||
'content': {
|
||||
'size': 0,
|
||||
'mimeType': '',
|
||||
'comment': '',
|
||||
'text': ''
|
||||
},
|
||||
'redirectURL': '',
|
||||
'headersSize': 0,
|
||||
'bodySize': 0,
|
||||
'comment': ''
|
||||
},
|
||||
'request': {
|
||||
'method': 'POST',
|
||||
'url': 'https://api.foss42.com/case/lower',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [],
|
||||
'headers': [
|
||||
{
|
||||
'name': 'Content-Type',
|
||||
'value': 'application/json',
|
||||
'comment': ''
|
||||
},
|
||||
{'name': 'User-Agent', 'value': 'Test Agent', 'comment': ''}
|
||||
],
|
||||
'postData': {
|
||||
'mimeType': 'application/json',
|
||||
'text': '{\n'
|
||||
'"text": "I LOVE Flutter"\n'
|
||||
'}',
|
||||
'comment': ''
|
||||
},
|
||||
'comment': '',
|
||||
'cookies': [],
|
||||
'headersSize': -1,
|
||||
'bodySize': 28
|
||||
},
|
||||
'cache': {}
|
||||
}
|
||||
],
|
||||
'comment': '',
|
||||
'browser': {'version': '1.0', 'comment': '', 'name': 'API Dash'},
|
||||
'version': '1.2'
|
||||
}
|
||||
};
|
||||
PackageInfo.setMockInitialValues(
|
||||
appName: "apidash",
|
||||
packageName: "dev.apidash.apidash",
|
||||
version: "1.0",
|
||||
buildNumber: "3",
|
||||
buildSignature: "XYZ");
|
||||
var result = await collectionToHAR([
|
||||
requestModelGet6,
|
||||
requestModelGet11,
|
||||
requestModelPost3,
|
||||
]);
|
||||
result['log']['entries'][0]['startedDateTime'] = 'ABC';
|
||||
result['log']['entries'][1]['startedDateTime'] = 'ABC';
|
||||
result['log']['entries'][2]['startedDateTime'] = 'ABC';
|
||||
expect(result, expectedResult);
|
||||
});
|
||||
|
||||
test('Test requestModelToHARJsonRequest', () {
|
||||
Map<String, dynamic> expectedResult = {
|
||||
'method': 'GET',
|
||||
'url': 'https://api.github.com/repos/foss42/apidash?raw=true',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [
|
||||
{'name': 'raw', 'value': 'true'}
|
||||
],
|
||||
'headers': [
|
||||
{'name': 'User-Agent', 'value': 'Test Agent'}
|
||||
]
|
||||
};
|
||||
expect(requestModelToHARJsonRequest(requestModelGet6), expectedResult);
|
||||
});
|
||||
|
||||
test('Test requestModelToHARJsonRequest exportMode=true', () {
|
||||
Map<String, dynamic> expectedResult = {
|
||||
'method': 'GET',
|
||||
'url': 'https://api.github.com/repos/foss42/apidash?raw=true',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [
|
||||
{'name': 'raw', 'value': 'true', 'comment': ''}
|
||||
],
|
||||
'headers': [
|
||||
{'name': 'User-Agent', 'value': 'Test Agent', 'comment': ''}
|
||||
],
|
||||
'comment': '',
|
||||
'cookies': [],
|
||||
'headersSize': -1,
|
||||
'bodySize': 0
|
||||
};
|
||||
expect(
|
||||
requestModelToHARJsonRequest(
|
||||
requestModelGet6,
|
||||
exportMode: true,
|
||||
),
|
||||
expectedResult);
|
||||
});
|
||||
|
||||
test('Test requestModelToHARJsonRequest exportMode=true', () {
|
||||
Map<String, dynamic> expectedResult = {
|
||||
'method': 'POST',
|
||||
'url': 'https://api.foss42.com/case/lower',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [],
|
||||
'headers': [
|
||||
{'name': 'Content-Type', 'value': 'application/json', 'comment': ''}
|
||||
],
|
||||
'postData': {
|
||||
'mimeType': 'application/json',
|
||||
'text': '{\n'
|
||||
'"text": "I LOVE Flutter"\n'
|
||||
'}',
|
||||
'comment': ''
|
||||
},
|
||||
'comment': '',
|
||||
'cookies': [],
|
||||
'headersSize': -1,
|
||||
'bodySize': 28
|
||||
};
|
||||
expect(
|
||||
requestModelToHARJsonRequest(
|
||||
requestModelPost2,
|
||||
exportMode: true,
|
||||
),
|
||||
expectedResult);
|
||||
});
|
||||
|
||||
test('Test requestModelToHARJsonRequest useEnabled=false', () {
|
||||
Map<String, dynamic> expectedResult = {
|
||||
'method': 'GET',
|
||||
'url':
|
||||
'https://api.foss42.com/humanize/social?num=8700000&digits=3&system=SS&add_space=true',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [
|
||||
{'name': 'num', 'value': '8700000'},
|
||||
{'name': 'digits', 'value': '3'},
|
||||
{'name': 'system', 'value': 'SS'},
|
||||
{'name': 'add_space', 'value': 'true'}
|
||||
],
|
||||
'headers': [
|
||||
{'name': 'User-Agent', 'value': 'Test Agent'},
|
||||
{'name': 'Content-Type', 'value': 'application/json'}
|
||||
]
|
||||
};
|
||||
expect(requestModelToHARJsonRequest(requestModelGet11), expectedResult);
|
||||
});
|
||||
|
||||
test('Test requestModelToHARJsonRequest useEnabled=true', () {
|
||||
Map<String, dynamic> expectedResult = {
|
||||
'method': 'GET',
|
||||
'url': 'https://api.foss42.com/humanize/social?num=8700000&digits=3',
|
||||
'httpVersion': 'HTTP/1.1',
|
||||
'queryString': [
|
||||
{'name': 'num', 'value': '8700000'},
|
||||
{'name': 'digits', 'value': '3'}
|
||||
],
|
||||
'headers': [
|
||||
{'name': 'User-Agent', 'value': 'Test Agent'}
|
||||
]
|
||||
};
|
||||
expect(
|
||||
requestModelToHARJsonRequest(
|
||||
requestModelGet11,
|
||||
useEnabled: true,
|
||||
),
|
||||
expectedResult);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
141
test/utils/header_utils_test.dart
Normal file
141
test/utils/header_utils_test.dart
Normal file
@ -0,0 +1,141 @@
|
||||
import 'package:apidash/utils/header_utils.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group("Testing getHeaderSuggestions function", () {
|
||||
test("Testing using Allow-Headers", () {
|
||||
String pattern = "Allow-Headers";
|
||||
List<String> expected = ["Access-Control-Allow-Headers"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Allow-Methods", () {
|
||||
String pattern = "Allow-Methods";
|
||||
List<String> expected = ["Access-Control-Allow-Methods"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Allow-Origin", () {
|
||||
String pattern = "Allow-Origin";
|
||||
List<String> expected = ["Access-Control-Allow-Origin"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Request-Method", () {
|
||||
String pattern = "Request-Method";
|
||||
List<String> expected = ["Access-Control-Request-Method"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Max-Age", () {
|
||||
String pattern = "Max-Age";
|
||||
List<String> expected = ["Access-Control-Max-Age"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Access-Control-Allow-Headers", () {
|
||||
String pattern = "Access-Control-Allow-Headers";
|
||||
List<String> expected = ["Access-Control-Allow-Headers"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Access-Control-Allow-Methods", () {
|
||||
String pattern = "Access-Control-Allow-Methods";
|
||||
List<String> expected = ["Access-Control-Allow-Methods"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Access-Control-Allow-Origin", () {
|
||||
String pattern = "Access-Control-Allow-Origin";
|
||||
List<String> expected = ["Access-Control-Allow-Origin"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Access-Control-Request-Method", () {
|
||||
String pattern = "Access-Control-Request-Method";
|
||||
List<String> expected = ["Access-Control-Request-Method"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Access-Control-Max-Age", () {
|
||||
String pattern = "Access-Control-Max-Age";
|
||||
List<String> expected = ["Access-Control-Max-Age"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Content-Type", () {
|
||||
String pattern = "Content-Type";
|
||||
List<String> expected = ['Content-Type', 'X-Content-Type-Options'];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using Expires", () {
|
||||
String pattern = "Expires";
|
||||
List<String> expected = ["Expires"];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using 'Access-Control' pattern", () {
|
||||
String pattern = "Access-Control";
|
||||
List<String> expected = [
|
||||
"Access-Control-Allow-Headers",
|
||||
"Access-Control-Allow-Methods",
|
||||
"Access-Control-Allow-Origin",
|
||||
"Access-Control-Max-Age",
|
||||
"Access-Control-Request-Headers",
|
||||
"Access-Control-Request-Method"
|
||||
];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using 'allow-' pattern", () {
|
||||
String pattern = 'allow-';
|
||||
List<String> expected = [
|
||||
"Access-Control-Allow-Headers",
|
||||
"Access-Control-Allow-Methods",
|
||||
"Access-Control-Allow-Origin"
|
||||
];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using 'content' pattern", () {
|
||||
String pattern = "content";
|
||||
List<String> expected = [
|
||||
'Content-Disposition',
|
||||
'Content-Encoding',
|
||||
'Content-Length',
|
||||
'Content-Security-Policy',
|
||||
'Content-Type',
|
||||
'X-Content-Type-Options'
|
||||
];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing using 'x-' pattern", () {
|
||||
String pattern = "x-";
|
||||
List<String> expected = [
|
||||
"Access-Control-Max-Age",
|
||||
"X-Api-Key",
|
||||
"X-Content-Type-Options",
|
||||
"X-CSRF-Token",
|
||||
"X-Forwarded-For",
|
||||
"X-Frame-Options",
|
||||
"X-Requested-With",
|
||||
"X-XSS-Protection"
|
||||
];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
|
||||
test("Testing for 'origin' pattern", () {
|
||||
String pattern = "origin";
|
||||
List<String> expected = [
|
||||
'Access-Control-Allow-Origin',
|
||||
'Cross-Origin-Embedder-Policy',
|
||||
'Cross-Origin-Opener-Policy',
|
||||
'Cross-Origin-Resource-Policy',
|
||||
'Origin'
|
||||
];
|
||||
expect(getHeaderSuggestions(pattern), expected);
|
||||
});
|
||||
});
|
||||
}
|
@ -268,7 +268,7 @@ void main() {
|
||||
test('Testing getResponseBodyViewOptions for image/svg+xml', () {
|
||||
MediaType mediaType5 = MediaType("image", "svg+xml");
|
||||
var result5 = getResponseBodyViewOptions(mediaType5);
|
||||
expect(result5.$1, kCodeRawBodyViewOptions);
|
||||
expect(result5.$1, kPreviewRawBodyViewOptions);
|
||||
expect(result5.$2, "xml");
|
||||
});
|
||||
test('Testing getResponseBodyViewOptions for application/xhtml+xml', () {
|
||||
|
@ -1 +1,6 @@
|
||||
import 'package:apidash/main.dart';
|
||||
import 'package:apidash/app.dart';
|
||||
import 'package:apidash/common/utils.dart';
|
||||
import 'package:apidash/screens/screens.dart';
|
||||
|
||||
void main() {}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/buttons.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import '../test_consts.dart';
|
||||
|
||||
void main() {
|
||||
@ -53,6 +54,7 @@ void main() {
|
||||
await tester.tap(button1);
|
||||
expect(changedValue, 'Send');
|
||||
});
|
||||
|
||||
testWidgets('Testing for Send Request button when sentRequestId is not null',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(
|
||||
@ -76,6 +78,7 @@ void main() {
|
||||
|
||||
expect(tester.widget<FilledButton>(button1).enabled, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Send Request button when sentRequestId = activeId',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(
|
||||
@ -99,4 +102,113 @@ void main() {
|
||||
|
||||
expect(tester.widget<FilledButton>(button1).enabled, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Save in Downloads button', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Save in Downloads button',
|
||||
theme: kThemeDataLight,
|
||||
home: const Scaffold(
|
||||
body: SaveInDownloadsButton(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.download), findsOneWidget);
|
||||
expect(find.text("Download"), findsOneWidget);
|
||||
|
||||
final button1 = find.byType(TextButton);
|
||||
expect(button1, findsOneWidget);
|
||||
|
||||
expect(tester.widget<TextButton>(button1).enabled, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Save in Downloads button 2', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Save in Downloads button',
|
||||
theme: kThemeDataLight,
|
||||
home: Scaffold(
|
||||
body: SaveInDownloadsButton(
|
||||
content: Uint8List.fromList([1]),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.download), findsOneWidget);
|
||||
expect(find.text("Download"), findsOneWidget);
|
||||
|
||||
final button1 = find.byType(TextButton);
|
||||
expect(button1, findsOneWidget);
|
||||
|
||||
expect(tester.widget<TextButton>(button1).enabled, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Repo button', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Repo button',
|
||||
theme: kThemeDataLight,
|
||||
home: const Scaffold(
|
||||
body: RepoButton(
|
||||
icon: Icons.code,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.code), findsOneWidget);
|
||||
expect(find.text("GitHub"), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Repo button icon = null', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Repo button',
|
||||
theme: kThemeDataLight,
|
||||
home: const Scaffold(
|
||||
body: RepoButton(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.code), findsNothing);
|
||||
expect(find.text("GitHub"), findsOneWidget);
|
||||
|
||||
final button1 = find.byType(FilledButton);
|
||||
expect(button1, findsOneWidget);
|
||||
|
||||
expect(tester.widget<FilledButton>(button1).enabled, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Discord button', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Discord button',
|
||||
theme: kThemeDataLight,
|
||||
home: const Scaffold(
|
||||
body: DiscordButton(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.discord), findsOneWidget);
|
||||
expect(find.text("Discord Server"), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Testing for Save button', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Save button',
|
||||
theme: kThemeDataLight,
|
||||
home: const Scaffold(
|
||||
body: SaveButton(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.save), findsOneWidget);
|
||||
expect(find.text("Save"), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
30
test/widgets/checkbox_test.dart
Normal file
30
test/widgets/checkbox_test.dart
Normal file
@ -0,0 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/checkbox.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Testing for Checkbox', (tester) async {
|
||||
dynamic changedValue;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Checkbox Widget',
|
||||
home: Scaffold(
|
||||
body: CheckBox(
|
||||
keyId: "1",
|
||||
value: false,
|
||||
onChanged: (value) {
|
||||
changedValue = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byKey(const Key("1")), findsOneWidget);
|
||||
var box = find.byKey(const Key("1"));
|
||||
await tester.tap(box);
|
||||
await tester.pump();
|
||||
await tester.pumpAndSettle();
|
||||
expect(changedValue, true);
|
||||
});
|
||||
}
|
@ -87,4 +87,88 @@ void main() {
|
||||
|
||||
expect(changedValue, ContentType.text);
|
||||
});
|
||||
|
||||
testWidgets('Testing Dropdown for FormData', (tester) async {
|
||||
dynamic changedValue;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Dropdown FormData Type testing',
|
||||
theme: kThemeDataLight,
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
DropdownButtonFormData(
|
||||
formDataType: FormDataType.file,
|
||||
onChanged: (value) {
|
||||
changedValue = value!;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.unfold_more_rounded), findsOneWidget);
|
||||
expect(find.byType(DropdownButton<FormDataType>), findsOneWidget);
|
||||
expect(
|
||||
(tester.widget(find.byType(DropdownButton<FormDataType>))
|
||||
as DropdownButton)
|
||||
.value,
|
||||
equals(FormDataType.file));
|
||||
|
||||
await tester.tap(find.text('file'));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
|
||||
await tester.tap(find.text('text').last);
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
|
||||
expect(changedValue, FormDataType.text);
|
||||
});
|
||||
|
||||
testWidgets('Testing Dropdown for Codegen', (tester) async {
|
||||
dynamic changedValue;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Dropdown Codegen Type testing',
|
||||
theme: kThemeDataLight,
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
DropdownButtonCodegenLanguage(
|
||||
codegenLanguage: CodegenLanguage.curl,
|
||||
onChanged: (value) {
|
||||
changedValue = value!;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byIcon(Icons.unfold_more_rounded), findsOneWidget);
|
||||
expect(find.byType(DropdownButton<CodegenLanguage>), findsOneWidget);
|
||||
expect(
|
||||
(tester.widget(find.byType(DropdownButton<CodegenLanguage>))
|
||||
as DropdownButton)
|
||||
.value,
|
||||
equals(CodegenLanguage.curl));
|
||||
|
||||
await tester.tap(find.text('cURL'));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
|
||||
await tester.tap(find.text('Dart (dio)').last);
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
|
||||
expect(changedValue, CodegenLanguage.dartDio);
|
||||
});
|
||||
}
|
||||
|
21
test/widgets/form_data_field_test.dart
Normal file
21
test/widgets/form_data_field_test.dart
Normal file
@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/form_data_field.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Testing for Form Data Widget', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
title: 'Form Data Field Widget',
|
||||
home: Scaffold(
|
||||
body: FormDataField(
|
||||
keyId: "1",
|
||||
initialValue: "Test Field",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text("Test Field"), findsOneWidget);
|
||||
});
|
||||
}
|
24
test/widgets/headerfield_test.dart
Normal file
24
test/widgets/headerfield_test.dart
Normal file
@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/headerfield.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Testing Header Field', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
title: 'Header Field',
|
||||
home: Scaffold(
|
||||
body: Column(children: [
|
||||
HeaderField(
|
||||
keyId: "1",
|
||||
initialValue: "X",
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byKey(const Key("1")), findsOneWidget);
|
||||
expect(find.text('X'), findsOneWidget);
|
||||
});
|
||||
}
|
16
test/widgets/markdown_test.dart
Normal file
16
test/widgets/markdown_test.dart
Normal file
@ -0,0 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/markdown.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Testing CustomMarkdown', (tester) async {
|
||||
const markdown = CustomMarkdown(data: """Is a markdown ~`star on github`~
|
||||
|
||||
#br
|
||||
#br
|
||||
|
||||
~`github repo`~ ~`Discord Server`~""");
|
||||
await tester.pumpWidget(markdown);
|
||||
//expectTextStrings(tester.allWidgets, <String>['Data1']);
|
||||
}, skip: true);
|
||||
}
|
@ -4,6 +4,7 @@ import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:printing/printing.dart' show PdfPreview;
|
||||
import 'package:flutter_svg/flutter_svg.dart' show SvgPicture;
|
||||
import '../test_consts.dart';
|
||||
|
||||
void main() {
|
||||
@ -169,4 +170,65 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(kAudioError), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Testing when type/subtype is image/svg+xml', (tester) async {
|
||||
String rawSvg =
|
||||
"""<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 166 202">
|
||||
<defs>
|
||||
<linearGradient id="triangleGradient">
|
||||
<stop offset="20%" stop-color="#000000" stop-opacity=".55" />
|
||||
<stop offset="85%" stop-color="#616161" stop-opacity=".01" />
|
||||
</linearGradient>
|
||||
<linearGradient id="rectangleGradient" x1="0%" x2="0%" y1="0%" y2="100%">
|
||||
<stop offset="20%" stop-color="#000000" stop-opacity=".15" />
|
||||
<stop offset="85%" stop-color="#616161" stop-opacity=".01" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="#42A5F5" fill-opacity=".8" d="M37.7 128.9 9.8 101 100.4 10.4 156.2 10.4"/>
|
||||
<path fill="#42A5F5" fill-opacity=".8" d="M156.2 94 100.4 94 79.5 114.9 107.4 142.8"/>
|
||||
<path fill="#0D47A1" d="M79.5 170.7 100.4 191.6 156.2 191.6 156.2 191.6 107.4 142.8"/>
|
||||
<g transform="matrix(0.7071, -0.7071, 0.7071, 0.7071, -77.667, 98.057)">
|
||||
<rect width="39.4" height="39.4" x="59.8" y="123.1" fill="#42A5F5" />
|
||||
<rect width="39.4" height="5.5" x="59.8" y="162.5" fill="url(#rectangleGradient)" />
|
||||
</g>
|
||||
<path d="M79.5 170.7 120.9 156.4 107.4 142.8" fill="url(#triangleGradient)" />
|
||||
</svg>""";
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(
|
||||
type: 'image',
|
||||
subtype: 'svg+xml',
|
||||
bytes: Uint8List.fromList([]),
|
||||
body: rawSvg,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(kSvgError), findsNothing);
|
||||
expect(find.byType(SvgPicture), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Testing when type/subtype is image/svg+xml corrupted',
|
||||
(tester) async {
|
||||
String rawSvg = "rwsjhdws";
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(
|
||||
type: 'image',
|
||||
subtype: 'svg+xml',
|
||||
bytes: Uint8List.fromList([]),
|
||||
body: rawSvg,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text(kSvgError), findsOneWidget);
|
||||
});
|
||||
}
|
||||
|
19
test/widgets/window_caption_test.dart
Normal file
19
test/widgets/window_caption_test.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/window_caption.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Testing for Window caption', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
title: 'Window caption',
|
||||
home: Scaffold(
|
||||
body: WindowCaption(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final wd = find.byType(GestureDetector);
|
||||
expect(wd, findsAny);
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user