mirror of
https://github.com/foss42/apidash.git
synced 2025-06-04 09:16:02 +08:00
Merge branch 'main' into refactor
This commit is contained in:
@ -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,120 +152,151 @@ 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(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await _copy(kEncoder.convert(widget.code), sm);
|
||||
},
|
||||
child: const Text('Copy'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: state.areAllExpanded() ? null : state.expandAll,
|
||||
child: const Text('Expand All'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: state.areAllCollapsed() ? null : state.collapseAll,
|
||||
child: const Text('Collapse All'),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: JsonDataExplorer(
|
||||
nodes: state.displayNodes,
|
||||
itemScrollController: itemScrollController,
|
||||
itemSpacing: 4,
|
||||
rootInformationBuilder: (context, node) =>
|
||||
rootInfoBox(context, node),
|
||||
collapsableToggleBuilder: (context, node) => AnimatedRotation(
|
||||
turns: node.isCollapsed ? -0.25 : 0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
trailingBuilder: (context, node) => node.isFocused
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(maxHeight: 18),
|
||||
icon: const Icon(
|
||||
Icons.copy,
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () async {
|
||||
await _copy(kEncoder.convert(toJson(node)), sm);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
valueStyleBuilder: (value, style) =>
|
||||
valueStyleOverride(context, value, style),
|
||||
theme: (Theme.of(context).brightness == Brightness.light)
|
||||
? dataExplorerThemeLight
|
||||
: dataExplorerThemeDark,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant),
|
||||
borderRadius: kBorderRadius8,
|
||||
),
|
||||
child: Row(
|
||||
builder: (context, state, child) {
|
||||
return LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
var maxRootNodeWidth =
|
||||
getJsonPreviewerMaxRootNodeWidth(constraints.maxWidth);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Icon(
|
||||
Icons.search,
|
||||
size: 18,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await _copy(kEncoder.convert(widget.code), sm);
|
||||
},
|
||||
child: const Text(
|
||||
'Copy',
|
||||
style: kTextStyleButtonSmall,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
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',
|
||||
style: kTextStyleButtonSmall,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: JsonSearchField(
|
||||
controller: searchController,
|
||||
onChanged: (term) => state.search(term),
|
||||
child: JsonDataExplorer(
|
||||
nodes: state.displayNodes,
|
||||
itemScrollController: itemScrollController,
|
||||
itemSpacing: 4,
|
||||
rootInformationBuilder: (context, node) =>
|
||||
rootInfoBox(context, node),
|
||||
collapsableToggleBuilder: (context, node) =>
|
||||
AnimatedRotation(
|
||||
turns: node.isCollapsed ? -0.25 : 0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
trailingBuilder: (context, node) => node.isFocused
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints:
|
||||
const BoxConstraints(maxHeight: 18),
|
||||
icon: const Icon(
|
||||
Icons.copy,
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () async {
|
||||
await _copy(
|
||||
kEncoder.convert(toJson(node)), sm);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
valueStyleBuilder: (value, style) =>
|
||||
valueStyleOverride(context, value, style),
|
||||
theme: (Theme.of(context).brightness == Brightness.light)
|
||||
? dataExplorerThemeLight
|
||||
: dataExplorerThemeDark,
|
||||
maxRootNodeWidth: maxRootNodeWidth,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.surfaceVariant),
|
||||
borderRadius: kBorderRadius8,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Icon(
|
||||
Icons.search,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: JsonSearchField(
|
||||
controller: searchController,
|
||||
onChanged: (term) => state.search(term),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
if (state.searchResults.isNotEmpty)
|
||||
Text(_searchFocusText(),
|
||||
style: Theme.of(context).textTheme.bodySmall),
|
||||
if (state.searchResults.isNotEmpty)
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () {
|
||||
store.focusPreviousSearchResult();
|
||||
_scrollToSearchMatch();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_drop_up),
|
||||
),
|
||||
if (state.searchResults.isNotEmpty)
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () {
|
||||
store.focusNextSearchResult();
|
||||
_scrollToSearchMatch();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (state.searchResults.isNotEmpty)
|
||||
Text(_searchFocusText(),
|
||||
style: Theme.of(context).textTheme.bodySmall),
|
||||
if (state.searchResults.isNotEmpty)
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () {
|
||||
store.focusPreviousSearchResult();
|
||||
_scrollToSearchMatch();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_drop_up),
|
||||
),
|
||||
if (state.searchResults.isNotEmpty)
|
||||
IconButton(
|
||||
visualDensity: VisualDensity.compact,
|
||||
onPressed: () {
|
||||
store.focusNextSearchResult();
|
||||
_scrollToSearchMatch();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -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(() {});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user