mirror of
https://github.com/foss42/apidash.git
synced 2025-10-18 12:13:31 +08:00
Refactor Intro Screen, Collection Pane & URL Card
This commit is contained in:
@ -179,6 +179,8 @@ const kDarkCodeTheme = {
|
|||||||
'variable': TextStyle(color: Color(0xffaddb67)),
|
'variable': TextStyle(color: Color(0xffaddb67)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RequestItemMenuOption { delete, duplicate }
|
||||||
|
|
||||||
enum HTTPVerb { get, head, post, put, patch, delete }
|
enum HTTPVerb { get, head, post, put, patch, delete }
|
||||||
|
|
||||||
enum ContentType { json, text }
|
enum ContentType { json, text }
|
||||||
@ -311,8 +313,6 @@ const Map<String, String> kCodeHighlighterMap = {
|
|||||||
kSubTypeTextYml: "yaml",
|
kSubTypeTextYml: "yaml",
|
||||||
};
|
};
|
||||||
|
|
||||||
const sendingIndicator = AssetImage("assets/sending.gif");
|
|
||||||
|
|
||||||
// HTTP response status codes
|
// HTTP response status codes
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
||||||
const kResponseCodeReasons = {
|
const kResponseCodeReasons = {
|
||||||
@ -403,3 +403,9 @@ const kUnexpectedRaiseIssue =
|
|||||||
|
|
||||||
const kRaiseIssue =
|
const kRaiseIssue =
|
||||||
"\nPlease raise an issue in API Dash GitHub repo so that we can resolve it.";
|
"\nPlease raise an issue in API Dash GitHub repo so that we can resolve it.";
|
||||||
|
|
||||||
|
const kHintTextUrlCard = "Enter API endpoint like api.foss42.com/country/codes";
|
||||||
|
const kLabelSend = "Send";
|
||||||
|
const kLabelSending = "Sending..";
|
||||||
|
const kLabelBusy = "Busy";
|
||||||
|
const kLabelCopy = "Copy";
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
import 'package:apidash/models/models.dart';
|
import 'package:apidash/models/models.dart';
|
||||||
import 'package:apidash/utils/utils.dart';
|
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class CollectionPane extends ConsumerStatefulWidget {
|
class CollectionPane extends ConsumerStatefulWidget {
|
||||||
@ -152,8 +152,6 @@ class _RequestListState extends ConsumerState<RequestList> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RequestItemMenuOption { delete, duplicate }
|
|
||||||
|
|
||||||
class RequestItem extends ConsumerStatefulWidget {
|
class RequestItem extends ConsumerStatefulWidget {
|
||||||
const RequestItem({
|
const RequestItem({
|
||||||
required this.id,
|
required this.id,
|
||||||
@ -176,107 +174,27 @@ class _RequestItemState extends ConsumerState<RequestItem> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Color color = Theme.of(context).colorScheme.surface;
|
final activeRequestId = ref.watch(activeIdStateProvider);
|
||||||
final Color surfaceTint = Theme.of(context).colorScheme.primary;
|
|
||||||
final activeRequest = ref.watch(activeIdStateProvider);
|
return SidebarRequestCard(
|
||||||
bool isActiveId = activeRequest == widget.id;
|
id: widget.id,
|
||||||
return Material(
|
activeRequestId: activeRequestId,
|
||||||
borderRadius: kBorderRadius12,
|
url: widget.requestModel.url,
|
||||||
elevation: isActiveId ? 1 : 0,
|
method: widget.requestModel.method,
|
||||||
surfaceTintColor: isActiveId ? surfaceTint : null,
|
onTap: () {
|
||||||
color: color,
|
ref.read(activeIdStateProvider.notifier).update((state) => widget.id);
|
||||||
type: MaterialType.card,
|
},
|
||||||
child: InkWell(
|
onMenuSelected: (RequestItemMenuOption item) {
|
||||||
borderRadius: kBorderRadius12,
|
if (item == RequestItemMenuOption.delete) {
|
||||||
onTap: () {
|
ref.read(activeIdStateProvider.notifier).update((state) => null);
|
||||||
ref.read(activeIdStateProvider.notifier).update((state) => widget.id);
|
ref.read(collectionStateNotifierProvider.notifier).remove(widget.id);
|
||||||
},
|
}
|
||||||
child: Padding(
|
if (item == RequestItemMenuOption.duplicate) {
|
||||||
padding: EdgeInsets.only(
|
ref
|
||||||
left: 10,
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
right: isActiveId ? 0 : 20,
|
.duplicate(widget.id);
|
||||||
top: 5,
|
}
|
||||||
bottom: 5,
|
},
|
||||||
),
|
|
||||||
child: SizedBox(
|
|
||||||
height: 20,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
MethodBox(method: widget.requestModel.method),
|
|
||||||
kHSpacer5,
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
getRequestTitleFromUrl(widget.requestModel.url),
|
|
||||||
softWrap: false,
|
|
||||||
overflow: TextOverflow.fade,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
|
||||||
visible: isActiveId,
|
|
||||||
child: PopupMenuButton<RequestItemMenuOption>(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
splashRadius: 14,
|
|
||||||
iconSize: 14,
|
|
||||||
onSelected: (RequestItemMenuOption item) {
|
|
||||||
if (item == RequestItemMenuOption.delete) {
|
|
||||||
ref
|
|
||||||
.read(activeIdStateProvider.notifier)
|
|
||||||
.update((state) => null);
|
|
||||||
ref
|
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
|
||||||
.remove(widget.id);
|
|
||||||
}
|
|
||||||
if (item == RequestItemMenuOption.duplicate) {
|
|
||||||
ref
|
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
|
||||||
.duplicate(widget.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
itemBuilder: (BuildContext context) =>
|
|
||||||
<PopupMenuEntry<RequestItemMenuOption>>[
|
|
||||||
const PopupMenuItem<RequestItemMenuOption>(
|
|
||||||
value: RequestItemMenuOption.delete,
|
|
||||||
child: Text('Delete'),
|
|
||||||
),
|
|
||||||
const PopupMenuItem<RequestItemMenuOption>(
|
|
||||||
value: RequestItemMenuOption.duplicate,
|
|
||||||
child: Text('Duplicate'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MethodBox extends StatelessWidget {
|
|
||||||
const MethodBox({super.key, required this.method});
|
|
||||||
final HTTPVerb method;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
String text = method.name.toUpperCase();
|
|
||||||
if (method == HTTPVerb.delete) {
|
|
||||||
text = "DEL";
|
|
||||||
}
|
|
||||||
return SizedBox(
|
|
||||||
width: 28,
|
|
||||||
child: Text(
|
|
||||||
text,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 8,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: getHTTPMethodColor(
|
|
||||||
method,
|
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
import 'details_card/details_card.dart';
|
import 'details_card/details_card.dart';
|
||||||
import 'url_card.dart';
|
import 'url_card.dart';
|
||||||
@ -49,233 +49,16 @@ class RequestEditorPaneHome extends ConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final isDarkMode = ref.watch(darkModeProvider);
|
final isDarkMode = ref.watch(darkModeProvider);
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
return IntroMessage(
|
||||||
vertical: 40,
|
isDarkMode: isDarkMode,
|
||||||
horizontal: 60,
|
onNew: () {
|
||||||
),
|
String newId = ref.read(collectionStateNotifierProvider.notifier).add();
|
||||||
child: ListView(
|
ref.read(activeIdStateProvider.notifier).update((state) => newId);
|
||||||
children: [
|
},
|
||||||
Row(
|
onModeToggle: () async {
|
||||||
children: [
|
await ref.read(darkModeProvider.notifier).toggle();
|
||||||
Expanded(
|
},
|
||||||
child: Text(
|
|
||||||
"Welcome to API Dash ⚡️",
|
|
||||||
style: Theme.of(context).textTheme.headlineLarge,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
kIntro,
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer10,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: "Please support this project by giving us a ",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: FilledButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
launchUrl(Uri.parse(kGitUrl));
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.star),
|
|
||||||
label: const Text(
|
|
||||||
'Star on GitHub',
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"Getting Started",
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: "Click on the ",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
String newId = ref
|
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
|
||||||
.add();
|
|
||||||
ref
|
|
||||||
.read(activeIdStateProvider.notifier)
|
|
||||||
.update((state) => newId);
|
|
||||||
},
|
|
||||||
child: const Text(
|
|
||||||
'+ New',
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: " button to start drafting a new API request.",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer10,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
const TextSpan(
|
|
||||||
text: "Choose your theme now: ",
|
|
||||||
),
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
onPressed: () async {
|
|
||||||
await ref.read(darkModeProvider.notifier).toggle();
|
|
||||||
},
|
|
||||||
icon: isDarkMode
|
|
||||||
? const Icon(Icons.dark_mode)
|
|
||||||
: const Icon(Icons.light_mode),
|
|
||||||
label: Text(
|
|
||||||
isDarkMode ? "Dark" : "Light",
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
kVSpacer10,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"Support Channel",
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: "Join our ",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: FilledButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
launchUrl(Uri.parse(kDiscordUrl));
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.discord),
|
|
||||||
label: const Text(
|
|
||||||
'Discord Server',
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(
|
|
||||||
text: " and drop a message in the #foss channel.",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
kVSpacer10,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
"Report Bug / Request New Feature",
|
|
||||||
style: Theme.of(context).textTheme.headlineSmall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
kVSpacer20,
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: "Just raise an issue in our ",
|
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
WidgetSpan(
|
|
||||||
alignment: PlaceholderAlignment.middle,
|
|
||||||
child: FilledButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
launchUrl(Uri.parse(kGitUrl));
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.code_rounded),
|
|
||||||
label: const Text(
|
|
||||||
'Github Repo',
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:apidash/providers/providers.dart';
|
import 'package:apidash/providers/providers.dart';
|
||||||
import 'package:apidash/utils/utils.dart';
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
import 'package:apidash/consts.dart';
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class EditorPaneRequestURLCard extends StatefulWidget {
|
class EditorPaneRequestURLCard extends StatefulWidget {
|
||||||
@ -43,7 +43,7 @@ class _EditorPaneRequestURLCardState extends State<EditorPaneRequestURLCard> {
|
|||||||
kHSpacer20,
|
kHSpacer20,
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 36,
|
height: 36,
|
||||||
child: SendRequestButton(),
|
child: SendButton(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -71,42 +71,16 @@ class _DropdownButtonHTTPMethodState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final surfaceColor = Theme.of(context).colorScheme.surface;
|
|
||||||
final activeId = ref.watch(activeIdStateProvider);
|
final activeId = ref.watch(activeIdStateProvider);
|
||||||
final method =
|
final method =
|
||||||
ref.watch(activeRequestModelProvider.select((value) => value?.method));
|
ref.watch(activeRequestModelProvider.select((value) => value?.method));
|
||||||
return DropdownButton<HTTPVerb>(
|
return DropdownButtonHttpMethod(
|
||||||
focusColor: surfaceColor,
|
method: method,
|
||||||
value: method,
|
|
||||||
icon: const Icon(Icons.unfold_more_rounded),
|
|
||||||
elevation: 4,
|
|
||||||
underline: Container(
|
|
||||||
height: 0,
|
|
||||||
),
|
|
||||||
borderRadius: kBorderRadius12,
|
|
||||||
onChanged: (HTTPVerb? value) {
|
onChanged: (HTTPVerb? value) {
|
||||||
ref
|
ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.update(activeId!, method: value);
|
.update(activeId!, method: value);
|
||||||
},
|
},
|
||||||
items: HTTPVerb.values.map<DropdownMenuItem<HTTPVerb>>((HTTPVerb value) {
|
|
||||||
return DropdownMenuItem<HTTPVerb>(
|
|
||||||
value: value,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16),
|
|
||||||
child: Text(
|
|
||||||
value.name.toUpperCase(),
|
|
||||||
style: kCodeStyle.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: getHTTPMethodColor(
|
|
||||||
value,
|
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,22 +103,12 @@ class _URLTextFieldState extends ConsumerState<URLTextField> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final activeId = ref.watch(activeIdStateProvider);
|
final activeId = ref.watch(activeIdStateProvider);
|
||||||
return TextFormField(
|
return URLField(
|
||||||
key: Key("url-${activeId!}"),
|
activeId: activeId!,
|
||||||
initialValue: ref
|
initialValue: ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.getRequestModel(activeId)
|
.getRequestModel(activeId)
|
||||||
.url,
|
.url,
|
||||||
style: kCodeStyle,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: "Enter API endpoint like api.foss42.com/country/codes",
|
|
||||||
hintStyle: kCodeStyle.copyWith(
|
|
||||||
color: Theme.of(context).colorScheme.outline.withOpacity(
|
|
||||||
kHintOpacity,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
border: InputBorder.none,
|
|
||||||
),
|
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
ref
|
ref
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
@ -154,16 +118,16 @@ class _URLTextFieldState extends ConsumerState<URLTextField> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SendRequestButton extends ConsumerStatefulWidget {
|
class SendButton extends ConsumerStatefulWidget {
|
||||||
const SendRequestButton({
|
const SendButton({
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<SendRequestButton> createState() => _SendRequestButtonState();
|
ConsumerState<SendButton> createState() => _SendButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SendRequestButtonState extends ConsumerState<SendRequestButton> {
|
class _SendButtonState extends ConsumerState<SendButton> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -173,31 +137,14 @@ class _SendRequestButtonState extends ConsumerState<SendRequestButton> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final activeId = ref.watch(activeIdStateProvider);
|
final activeId = ref.watch(activeIdStateProvider);
|
||||||
final sentRequestId = ref.watch(sentRequestIdStateProvider);
|
final sentRequestId = ref.watch(sentRequestIdStateProvider);
|
||||||
bool disable = sentRequestId != null;
|
return SendRequestButton(
|
||||||
return FilledButton(
|
activeId: activeId,
|
||||||
onPressed: disable
|
sentRequestId: sentRequestId,
|
||||||
? null
|
onTap: () {
|
||||||
: () {
|
ref
|
||||||
ref
|
.read(collectionStateNotifierProvider.notifier)
|
||||||
.read(collectionStateNotifierProvider.notifier)
|
.sendRequest(activeId!);
|
||||||
.sendRequest(activeId!);
|
},
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
disable
|
|
||||||
? (activeId == sentRequestId ? "Sending.." : "Busy")
|
|
||||||
: "Send",
|
|
||||||
style: kTextStyleButton,
|
|
||||||
),
|
|
||||||
if (!disable) kHSpacer10,
|
|
||||||
if (!disable)
|
|
||||||
const Icon(
|
|
||||||
size: 16,
|
|
||||||
Icons.send,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:multi_split_view/multi_split_view.dart';
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
import 'package:apidash/consts.dart';
|
|
||||||
import 'editor_pane/editor_pane.dart';
|
import 'editor_pane/editor_pane.dart';
|
||||||
import 'collection_pane.dart';
|
import 'collection_pane.dart';
|
||||||
|
|
||||||
@ -12,53 +11,11 @@ class HomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class HomePageState extends State<HomePage> {
|
class HomePageState extends State<HomePage> {
|
||||||
final MultiSplitViewController _controller = MultiSplitViewController(
|
|
||||||
areas: [
|
|
||||||
Area(size: 250, minimalSize: 200),
|
|
||||||
Area(minimalWeight: 0.7),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return const DashboardSplitView(
|
||||||
body: Column(
|
sidebarWidget: CollectionPane(),
|
||||||
children: [
|
mainWidget: RequestEditorPane(),
|
||||||
Expanded(
|
|
||||||
child: MultiSplitViewTheme(
|
|
||||||
data: MultiSplitViewThemeData(
|
|
||||||
dividerThickness: 3,
|
|
||||||
dividerPainter: DividerPainters.background(
|
|
||||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
|
||||||
highlightedColor:
|
|
||||||
Theme.of(context).colorScheme.outline.withOpacity(
|
|
||||||
kHintOpacity,
|
|
||||||
),
|
|
||||||
animationEnabled: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: MultiSplitView(
|
|
||||||
controller: _controller,
|
|
||||||
children: const [
|
|
||||||
CollectionPane(),
|
|
||||||
RequestEditorPane(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
class CopyButton extends StatefulWidget {
|
class CopyButton extends StatefulWidget {
|
||||||
const CopyButton({super.key, required this.toCopy});
|
const CopyButton({super.key, required this.toCopy});
|
||||||
@ -22,7 +23,56 @@ class _CopyButtonState extends State<CopyButton> {
|
|||||||
Icons.content_copy,
|
Icons.content_copy,
|
||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
Text("Copy")
|
Text(kLabelCopy)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendRequestButton extends StatefulWidget {
|
||||||
|
const SendRequestButton({
|
||||||
|
super.key,
|
||||||
|
required this.activeId,
|
||||||
|
required this.sentRequestId,
|
||||||
|
required this.onTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String? activeId;
|
||||||
|
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;
|
||||||
|
return FilledButton(
|
||||||
|
onPressed: disable ? null : widget.onTap,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
disable
|
||||||
|
? (widget.activeId == widget.sentRequestId
|
||||||
|
? kLabelSending
|
||||||
|
: kLabelBusy)
|
||||||
|
: kLabelSend,
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
if (!disable) kHSpacer10,
|
||||||
|
if (!disable)
|
||||||
|
const Icon(
|
||||||
|
size: 16,
|
||||||
|
Icons.send,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
77
lib/widgets/cards.dart
Normal file
77
lib/widgets/cards.dart
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
import 'package:apidash/utils/utils.dart';
|
||||||
|
import 'menus.dart' show RequestCardMenu;
|
||||||
|
import 'texts.dart' show MethodBox;
|
||||||
|
|
||||||
|
class SidebarRequestCard extends StatefulWidget {
|
||||||
|
const SidebarRequestCard({
|
||||||
|
super.key,
|
||||||
|
required this.id,
|
||||||
|
required this.activeRequestId,
|
||||||
|
required this.url,
|
||||||
|
required this.method,
|
||||||
|
this.onTap,
|
||||||
|
this.onMenuSelected,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final String? activeRequestId;
|
||||||
|
final String url;
|
||||||
|
final HTTPVerb method;
|
||||||
|
final void Function()? onTap;
|
||||||
|
final Function(RequestItemMenuOption)? onMenuSelected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SidebarRequestCard> createState() => _SidebarRequestCardState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SidebarRequestCardState extends State<SidebarRequestCard> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final Color color = Theme.of(context).colorScheme.surface;
|
||||||
|
final Color surfaceTint = Theme.of(context).colorScheme.primary;
|
||||||
|
bool isActiveId = widget.activeRequestId == widget.id;
|
||||||
|
return Material(
|
||||||
|
borderRadius: kBorderRadius12,
|
||||||
|
elevation: isActiveId ? 1 : 0,
|
||||||
|
surfaceTintColor: isActiveId ? surfaceTint : null,
|
||||||
|
color: color,
|
||||||
|
type: MaterialType.card,
|
||||||
|
child: InkWell(
|
||||||
|
borderRadius: kBorderRadius12,
|
||||||
|
onTap: widget.onTap,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: 10,
|
||||||
|
right: isActiveId ? 0 : 20,
|
||||||
|
top: 5,
|
||||||
|
bottom: 5,
|
||||||
|
),
|
||||||
|
child: SizedBox(
|
||||||
|
height: 20,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
MethodBox(method: widget.method),
|
||||||
|
kHSpacer5,
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
getRequestTitleFromUrl(widget.url),
|
||||||
|
softWrap: false,
|
||||||
|
overflow: TextOverflow.fade,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Visibility(
|
||||||
|
visible: isActiveId,
|
||||||
|
child: RequestCardMenu(
|
||||||
|
onSelected: widget.onMenuSelected,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
59
lib/widgets/dropdowns.dart
Normal file
59
lib/widgets/dropdowns.dart
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/utils/utils.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class DropdownButtonHttpMethod extends StatefulWidget {
|
||||||
|
const DropdownButtonHttpMethod({
|
||||||
|
super.key,
|
||||||
|
this.method,
|
||||||
|
this.onChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
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,
|
||||||
|
icon: const Icon(Icons.unfold_more_rounded),
|
||||||
|
elevation: 4,
|
||||||
|
underline: Container(
|
||||||
|
height: 0,
|
||||||
|
),
|
||||||
|
borderRadius: kBorderRadius12,
|
||||||
|
onChanged: widget.onChanged,
|
||||||
|
items: HTTPVerb.values.map<DropdownMenuItem<HTTPVerb>>((HTTPVerb value) {
|
||||||
|
return DropdownMenuItem<HTTPVerb>(
|
||||||
|
value: value,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 16),
|
||||||
|
child: Text(
|
||||||
|
value.name.toUpperCase(),
|
||||||
|
style: kCodeStyle.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: getHTTPMethodColor(
|
||||||
|
value,
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
244
lib/widgets/intro_message.dart
Normal file
244
lib/widgets/intro_message.dart
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class IntroMessage extends StatefulWidget {
|
||||||
|
const IntroMessage({
|
||||||
|
super.key,
|
||||||
|
required this.isDarkMode,
|
||||||
|
this.onNew,
|
||||||
|
this.onModeToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
final bool isDarkMode;
|
||||||
|
final void Function()? onNew;
|
||||||
|
final void Function()? onModeToggle;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<IntroMessage> createState() => _IntroMessageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _IntroMessageState extends State<IntroMessage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
vertical: 40,
|
||||||
|
horizontal: 60,
|
||||||
|
),
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Welcome to API Dash ⚡️",
|
||||||
|
style: Theme.of(context).textTheme.headlineLarge,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
kIntro,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer10,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: "Please support this project by giving us a ",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: FilledButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
launchUrl(Uri.parse(kGitUrl));
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.star),
|
||||||
|
label: const Text(
|
||||||
|
'Star on GitHub',
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Getting Started",
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: "Click on the ",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: widget.onNew,
|
||||||
|
child: const Text(
|
||||||
|
'+ New',
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: " button to start drafting a new API request.",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer10,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: "Choose your theme now: ",
|
||||||
|
),
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
onPressed: widget.onModeToggle,
|
||||||
|
icon: widget.isDarkMode
|
||||||
|
? const Icon(Icons.dark_mode)
|
||||||
|
: const Icon(Icons.light_mode),
|
||||||
|
label: Text(
|
||||||
|
widget.isDarkMode ? "Dark" : "Light",
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
kVSpacer10,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Support Channel",
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: "Join our ",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: FilledButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
launchUrl(Uri.parse(kDiscordUrl));
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.discord),
|
||||||
|
label: const Text(
|
||||||
|
'Discord Server',
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: " and drop a message in the #foss channel.",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
kVSpacer10,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
"Report Bug / Request New Feature",
|
||||||
|
style: Theme.of(context).textTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
kVSpacer20,
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: "Just raise an issue in our ",
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
WidgetSpan(
|
||||||
|
alignment: PlaceholderAlignment.middle,
|
||||||
|
child: FilledButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
launchUrl(Uri.parse(kGitUrl));
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.code_rounded),
|
||||||
|
label: const Text(
|
||||||
|
'Github Repo',
|
||||||
|
style: kTextStyleButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
37
lib/widgets/menus.dart
Normal file
37
lib/widgets/menus.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class RequestCardMenu extends StatefulWidget {
|
||||||
|
const RequestCardMenu({
|
||||||
|
super.key,
|
||||||
|
this.onSelected,
|
||||||
|
});
|
||||||
|
|
||||||
|
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,
|
||||||
|
itemBuilder: (BuildContext context) =>
|
||||||
|
<PopupMenuEntry<RequestItemMenuOption>>[
|
||||||
|
const PopupMenuItem<RequestItemMenuOption>(
|
||||||
|
value: RequestItemMenuOption.delete,
|
||||||
|
child: Text('Delete'),
|
||||||
|
),
|
||||||
|
const PopupMenuItem<RequestItemMenuOption>(
|
||||||
|
value: RequestItemMenuOption.duplicate,
|
||||||
|
child: Text('Duplicate'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
69
lib/widgets/splitviews.dart
Normal file
69
lib/widgets/splitviews.dart
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:multi_split_view/multi_split_view.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class DashboardSplitView extends StatefulWidget {
|
||||||
|
const DashboardSplitView({
|
||||||
|
Key? key,
|
||||||
|
required this.sidebarWidget,
|
||||||
|
required this.mainWidget,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Widget sidebarWidget;
|
||||||
|
final Widget mainWidget;
|
||||||
|
|
||||||
|
@override
|
||||||
|
DashboardSplitViewState createState() => DashboardSplitViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class DashboardSplitViewState extends State<DashboardSplitView> {
|
||||||
|
final MultiSplitViewController _controller = MultiSplitViewController(
|
||||||
|
areas: [
|
||||||
|
Area(size: 250, minimalSize: 200),
|
||||||
|
Area(minimalWeight: 0.7),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: MultiSplitViewTheme(
|
||||||
|
data: MultiSplitViewThemeData(
|
||||||
|
dividerThickness: 3,
|
||||||
|
dividerPainter: DividerPainters.background(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||||
|
highlightedColor:
|
||||||
|
Theme.of(context).colorScheme.outline.withOpacity(
|
||||||
|
kHintOpacity,
|
||||||
|
),
|
||||||
|
animationEnabled: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: MultiSplitView(
|
||||||
|
controller: _controller,
|
||||||
|
children: [
|
||||||
|
widget.sidebarWidget,
|
||||||
|
widget.mainWidget,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
44
lib/widgets/textfields.dart
Normal file
44
lib/widgets/textfields.dart
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class URLField extends StatefulWidget {
|
||||||
|
const URLField({
|
||||||
|
super.key,
|
||||||
|
required this.activeId,
|
||||||
|
this.initialValue,
|
||||||
|
this.onChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String activeId;
|
||||||
|
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,
|
||||||
|
style: kCodeStyle,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: kHintTextUrlCard,
|
||||||
|
hintStyle: kCodeStyle.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.outline.withOpacity(
|
||||||
|
kHintOpacity,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
border: InputBorder.none,
|
||||||
|
),
|
||||||
|
onChanged: widget.onChanged,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
30
lib/widgets/texts.dart
Normal file
30
lib/widgets/texts.dart
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:apidash/utils/utils.dart';
|
||||||
|
import 'package:apidash/consts.dart';
|
||||||
|
|
||||||
|
class MethodBox extends StatelessWidget {
|
||||||
|
const MethodBox({super.key, required this.method});
|
||||||
|
final HTTPVerb method;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
String text = method.name.toUpperCase();
|
||||||
|
if (method == HTTPVerb.delete) {
|
||||||
|
text = "DEL";
|
||||||
|
}
|
||||||
|
return SizedBox(
|
||||||
|
width: 28,
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 8,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: getHTTPMethodColor(
|
||||||
|
method,
|
||||||
|
brightness: Theme.of(context).brightness,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -6,3 +6,10 @@ export 'code_previewer.dart';
|
|||||||
export 'codegen_previewer.dart';
|
export 'codegen_previewer.dart';
|
||||||
export 'error_message.dart';
|
export 'error_message.dart';
|
||||||
export 'sending_widget.dart';
|
export 'sending_widget.dart';
|
||||||
|
export 'dropdowns.dart';
|
||||||
|
export 'splitviews.dart';
|
||||||
|
export 'texts.dart';
|
||||||
|
export 'textfields.dart';
|
||||||
|
export 'menus.dart';
|
||||||
|
export 'cards.dart';
|
||||||
|
export 'intro_message.dart';
|
||||||
|
Reference in New Issue
Block a user