mirror of
https://github.com/foss42/apidash.git
synced 2025-05-24 01:36:46 +08:00
wip: history panes
This commit is contained in:
@ -9,6 +9,7 @@ final navRailIndexStateProvider = StateProvider<int>((ref) => 0);
|
||||
final selectedIdEditStateProvider = StateProvider<String?>((ref) => null);
|
||||
final environmentFieldEditStateProvider = StateProvider<String?>((ref) => null);
|
||||
final codePaneVisibleStateProvider = StateProvider<bool>((ref) => false);
|
||||
final historyCodePaneVisibleStateProvider = StateProvider<bool>((ref) => false);
|
||||
final saveDataStateProvider = StateProvider<bool>((ref) => false);
|
||||
final clearDataStateProvider = StateProvider<bool>((ref) => false);
|
||||
final hasUnsavedChangesProvider = StateProvider<bool>((ref) => false);
|
||||
|
@ -9,14 +9,24 @@ import 'package:apidash/consts.dart';
|
||||
final Codegen codegen = Codegen();
|
||||
|
||||
class CodePane extends ConsumerWidget {
|
||||
const CodePane({super.key});
|
||||
const CodePane({
|
||||
super.key,
|
||||
this.isHistoryRequest = false,
|
||||
});
|
||||
|
||||
final bool isHistoryRequest;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final CodegenLanguage codegenLanguage =
|
||||
ref.watch(codegenLanguageStateProvider);
|
||||
|
||||
final selectedRequestModel = ref.watch(selectedRequestModelProvider);
|
||||
final selectedHistoryRequestModel =
|
||||
ref.watch(selectedHistoryRequestModelProvider);
|
||||
|
||||
final selectedRequestModel = isHistoryRequest
|
||||
? getRequestModelFromHistoryModel(selectedHistoryRequestModel!)
|
||||
: ref.watch(selectedRequestModelProvider);
|
||||
final defaultUriScheme =
|
||||
ref.watch(settingsProvider.select((value) => value.defaultUriScheme));
|
||||
|
@ -1,4 +1,5 @@
|
||||
export 'button_navbar.dart';
|
||||
export 'code_pane.dart';
|
||||
export 'editor_title.dart';
|
||||
export 'editor_title_actions.dart';
|
||||
export 'envfield_url.dart';
|
||||
|
60
lib/screens/history/details_pane/his_request_pane.dart
Normal file
60
lib/screens/history/details_pane/his_request_pane.dart
Normal file
@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class HistoryRequestPane extends ConsumerWidget {
|
||||
const HistoryRequestPane({
|
||||
super.key,
|
||||
this.isCompact = false,
|
||||
});
|
||||
|
||||
final bool isCompact;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final selectedId = ref.watch(selectedHistoryIdStateProvider);
|
||||
final codePaneVisible = ref.watch(historyCodePaneVisibleStateProvider);
|
||||
|
||||
final headersMap = ref.watch(selectedHistoryRequestModelProvider
|
||||
.select((value) => value?.httpRequestModel.headersMap)) ??
|
||||
{};
|
||||
final headerLength = headersMap.length;
|
||||
|
||||
final paramsMap = ref.watch(selectedHistoryRequestModelProvider
|
||||
.select((value) => value?.httpRequestModel.paramsMap)) ??
|
||||
{};
|
||||
final paramLength = paramsMap.length;
|
||||
|
||||
final hasBody = ref.watch(selectedHistoryRequestModelProvider
|
||||
.select((value) => value?.httpRequestModel.hasBody)) ??
|
||||
false;
|
||||
|
||||
return RequestPane(
|
||||
selectedId: selectedId,
|
||||
codePaneVisible: codePaneVisible,
|
||||
onPressedCodeButton: () {
|
||||
ref.read(historyCodePaneVisibleStateProvider.notifier).state =
|
||||
!codePaneVisible;
|
||||
},
|
||||
showViewCodeButton: !isCompact,
|
||||
showIndicators: [
|
||||
paramLength > 0,
|
||||
headerLength > 0,
|
||||
hasBody,
|
||||
],
|
||||
children: [
|
||||
RequestDataTable(
|
||||
rows: paramsMap,
|
||||
keyName: kNameURLParam,
|
||||
),
|
||||
RequestDataTable(
|
||||
rows: headersMap,
|
||||
keyName: kNameHeader,
|
||||
),
|
||||
const SizedBox(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
48
lib/screens/history/details_pane/his_response_pane.dart
Normal file
48
lib/screens/history/details_pane/his_response_pane.dart
Normal file
@ -0,0 +1,48 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/utils/utils.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class HistoryResponsePane extends ConsumerWidget {
|
||||
const HistoryResponsePane({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final selectedId = ref.watch(selectedHistoryIdStateProvider);
|
||||
final selectedHistoryRequest =
|
||||
ref.watch(selectedHistoryRequestModelProvider);
|
||||
final historyHttpResponseModel = selectedHistoryRequest?.httpResponseModel;
|
||||
|
||||
if (selectedId != null) {
|
||||
final requestModel =
|
||||
getRequestModelFromHistoryModel(selectedHistoryRequest!);
|
||||
return Column(
|
||||
children: [
|
||||
ResponsePaneHeader(
|
||||
responseStatus: historyHttpResponseModel?.statusCode,
|
||||
message: kResponseCodeReasons[historyHttpResponseModel?.statusCode],
|
||||
time: historyHttpResponseModel?.time,
|
||||
),
|
||||
Expanded(
|
||||
child: ResponseTabView(
|
||||
selectedId: selectedId,
|
||||
children: [
|
||||
ResponseBody(
|
||||
selectedRequestModel: requestModel,
|
||||
),
|
||||
ResponseHeaders(
|
||||
responseHeaders: historyHttpResponseModel?.headers ?? {},
|
||||
requestHeaders:
|
||||
historyHttpResponseModel?.requestHeaders ?? {},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const Text("No Request Selected");
|
||||
}
|
||||
}
|
@ -49,9 +49,8 @@ class HistoryURLCard extends StatelessWidget {
|
||||
),
|
||||
isCompact ? kHSpacer10 : kHSpacer20,
|
||||
Expanded(
|
||||
child: RawTextField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: url),
|
||||
child: ReadOnlyTextField(
|
||||
initialValue: url,
|
||||
style: kCodeStyle.copyWith(
|
||||
fontSize: fontSize,
|
||||
),
|
||||
|
@ -4,7 +4,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import './details_pane/url_card.dart';
|
||||
import 'package:apidash/screens/common_widgets/common_widgets.dart';
|
||||
import 'details_pane/url_card.dart';
|
||||
import 'details_pane/his_request_pane.dart';
|
||||
import 'details_pane/his_response_pane.dart';
|
||||
|
||||
class HistoryDetails extends StatefulHookConsumerWidget {
|
||||
const HistoryDetails({super.key});
|
||||
@ -21,22 +24,62 @@ class _HistoryDetailsState extends ConsumerState<HistoryDetails>
|
||||
ref.watch(selectedHistoryRequestModelProvider);
|
||||
final metaData = selectedHistoryRequest?.metaData;
|
||||
|
||||
final codePaneVisible = ref.watch(historyCodePaneVisibleStateProvider);
|
||||
|
||||
final TabController controller =
|
||||
useTabController(initialLength: 2, vsync: this);
|
||||
|
||||
return selectedHistoryRequest != null
|
||||
? Column(
|
||||
? LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final isCompact = constraints.maxWidth < kMediumWindowWidth;
|
||||
return Column(
|
||||
children: [
|
||||
kVSpacer5,
|
||||
Padding(
|
||||
padding: kP4,
|
||||
padding: kPh4,
|
||||
child: HistoryURLCard(
|
||||
method: metaData!.method, url: metaData.url)),
|
||||
method: metaData!.method,
|
||||
url: metaData.url,
|
||||
)),
|
||||
kVSpacer10,
|
||||
if (isCompact) ...[
|
||||
RequestResponseTabbar(
|
||||
controller: controller,
|
||||
),
|
||||
kVSpacer10,
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: controller,
|
||||
children: [
|
||||
HistoryRequestPane(
|
||||
isCompact: isCompact,
|
||||
),
|
||||
const HistoryResponsePane(),
|
||||
],
|
||||
))
|
||||
] else ...[
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: kPh4,
|
||||
child: RequestDetailsCard(
|
||||
child: EqualSplitView(
|
||||
leftWidget: HistoryRequestPane(
|
||||
isCompact: isCompact,
|
||||
),
|
||||
rightWidget: codePaneVisible
|
||||
? const CodePane(isHistoryRequest: true)
|
||||
: const HistoryResponsePane(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
kVSpacer8,
|
||||
]
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
: const Text("No Request Selected");
|
||||
: const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/extensions/extensions.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/utils/utils.dart';
|
||||
import 'history_pane.dart';
|
||||
import 'history_viewer.dart';
|
||||
|
||||
@ -16,11 +17,14 @@ class HistoryPage extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final historyModel = ref.watch(selectedHistoryRequestModelProvider);
|
||||
final title = historyModel != null
|
||||
? getHistoryRequestName(historyModel.metaData)
|
||||
: 'History';
|
||||
if (context.isMediumWindow) {
|
||||
return DrawerSplitView(
|
||||
scaffoldKey: scaffoldKey,
|
||||
mainContent: const HistoryViewer(),
|
||||
title: Text(historyModel?.historyId ?? 'History'),
|
||||
title: Text(title),
|
||||
leftDrawerContent: const HistoryPane(),
|
||||
actions: const [SizedBox(width: 16)],
|
||||
onDrawerChanged: (value) =>
|
||||
|
@ -56,6 +56,7 @@ class HistoryList extends HookConsumerWidget {
|
||||
title: Text(
|
||||
humanizeDate(date),
|
||||
),
|
||||
initiallyExpanded: true,
|
||||
children: requestGroups.values.map((item) {
|
||||
return Padding(
|
||||
padding: kPv2 + kPh4,
|
||||
@ -79,9 +80,11 @@ class HistoryList extends HookConsumerWidget {
|
||||
);
|
||||
}).toList()
|
||||
: [
|
||||
const Text(
|
||||
const Center(
|
||||
child: Text(
|
||||
'No history',
|
||||
style: TextStyle(color: Colors.grey),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/providers/history_providers.dart';
|
||||
import 'package:apidash/utils/history_utils.dart';
|
||||
@ -10,23 +11,29 @@ class HistoryRequests extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final selectedRequestId = ref.watch(selectedHistoryIdStateProvider);
|
||||
final selectedRequest = ref.read(selectedHistoryRequestModelProvider);
|
||||
final historyMetas = ref.read(historyMetaStateNotifier);
|
||||
final selectedRequest = ref.watch(selectedHistoryRequestModelProvider);
|
||||
final historyMetas = ref.watch(historyMetaStateNotifier);
|
||||
final requestGroup = getRequestGroup(
|
||||
historyMetas?.values.toList(), selectedRequest?.metaData);
|
||||
return Column(
|
||||
children: requestGroup
|
||||
.map((request) => SidebarHistoryCard(
|
||||
children: [
|
||||
kVSpacer20,
|
||||
...requestGroup.map((request) => Padding(
|
||||
padding: kPv2 + kPh4,
|
||||
child: HistoryRequestCard(
|
||||
id: request.historyId,
|
||||
method: request.method,
|
||||
model: request,
|
||||
isSelected: selectedRequestId == request.historyId,
|
||||
onTap: () {
|
||||
ref.read(selectedHistoryIdStateProvider.notifier).state =
|
||||
request.historyId;
|
||||
ref
|
||||
.read(historyMetaStateNotifier.notifier)
|
||||
.loadHistoryRequest(request.historyId);
|
||||
},
|
||||
models: [request],
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/screens/common_widgets/common_widgets.dart';
|
||||
import 'request_pane/request_pane.dart';
|
||||
import 'response_pane.dart';
|
||||
import 'code_pane.dart';
|
||||
|
||||
class EditorPaneRequestDetailsCard extends ConsumerWidget {
|
||||
const EditorPaneRequestDetailsCard({super.key});
|
||||
|
@ -7,7 +7,6 @@ import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import '../../home_page/collection_pane.dart';
|
||||
import '../../home_page/editor_pane/url_card.dart';
|
||||
import '../../home_page/editor_pane/details_card/code_pane.dart';
|
||||
import '../../home_page/editor_pane/editor_default.dart';
|
||||
import '../../common_widgets/common_widgets.dart';
|
||||
import '../widgets/page_base.dart';
|
||||
|
@ -13,6 +13,13 @@ String humanizeDate(DateTime? date) {
|
||||
return DateFormat('MMMM d, yyyy').format(date);
|
||||
}
|
||||
|
||||
String humanizeTime(DateTime? time) {
|
||||
if (time == null) {
|
||||
return "";
|
||||
}
|
||||
return DateFormat('hh:mm:ss a').format(time);
|
||||
}
|
||||
|
||||
String humanizeDuration(Duration? duration) {
|
||||
if (duration == null) {
|
||||
return "";
|
||||
|
@ -1,10 +1,22 @@
|
||||
import 'package:apidash/models/models.dart';
|
||||
import 'package:apidash/utils/convert_utils.dart';
|
||||
import 'package:apidash/models/models.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
DateTime stripTime(DateTime dateTime) {
|
||||
return DateTime(dateTime.year, dateTime.month, dateTime.day);
|
||||
}
|
||||
|
||||
RequestModel getRequestModelFromHistoryModel(HistoryRequestModel model) {
|
||||
return RequestModel(
|
||||
id: model.historyId,
|
||||
name: model.metaData.name,
|
||||
responseStatus: model.httpResponseModel.statusCode,
|
||||
message: kResponseCodeReasons[model.httpResponseModel.statusCode],
|
||||
httpRequestModel: model.httpRequestModel,
|
||||
httpResponseModel: model.httpResponseModel,
|
||||
);
|
||||
}
|
||||
|
||||
String getHistoryRequestName(HistoryMetaModel model) {
|
||||
if (model.name.isNotEmpty) {
|
||||
return model.name;
|
||||
|
65
lib/widgets/card_history_request.dart
Normal file
65
lib/widgets/card_history_request.dart
Normal file
@ -0,0 +1,65 @@
|
||||
import 'package:apidash/models/history_meta_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/utils/utils.dart';
|
||||
import 'texts.dart';
|
||||
|
||||
class HistoryRequestCard extends StatelessWidget {
|
||||
const HistoryRequestCard({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.model,
|
||||
this.isSelected = false,
|
||||
this.onTap,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final HistoryMetaModel model;
|
||||
final bool isSelected;
|
||||
final Function()? onTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color color = Theme.of(context).colorScheme.surface;
|
||||
final Color colorVariant =
|
||||
Theme.of(context).colorScheme.surfaceContainerHighest.withOpacity(0.5);
|
||||
final Color surfaceTint = Theme.of(context).colorScheme.primary;
|
||||
return Card(
|
||||
shape: const ContinuousRectangleBorder(borderRadius: kBorderRadius12),
|
||||
elevation: isSelected ? 1 : 0,
|
||||
surfaceTintColor: isSelected ? surfaceTint : null,
|
||||
color: isSelected
|
||||
? Theme.of(context).colorScheme.brightness == Brightness.dark
|
||||
? colorVariant
|
||||
: color
|
||||
: color,
|
||||
margin: EdgeInsets.zero,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: kBorderRadius6,
|
||||
hoverColor: colorVariant,
|
||||
focusColor: colorVariant.withOpacity(0.5),
|
||||
child: Padding(
|
||||
padding: kPv6 + kPh8,
|
||||
child: SizedBox(
|
||||
height: 20,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
humanizeTime(model.timeStamp),
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
style: kCodeStyle,
|
||||
),
|
||||
),
|
||||
kHSpacer4,
|
||||
StatusCode(statusCode: model.responseStatus),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
30
lib/widgets/field_read_only.dart
Normal file
30
lib/widgets/field_read_only.dart
Normal file
@ -0,0 +1,30 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class ReadOnlyTextField extends StatelessWidget {
|
||||
const ReadOnlyTextField({
|
||||
super.key,
|
||||
this.initialValue,
|
||||
this.style,
|
||||
this.decoration,
|
||||
});
|
||||
|
||||
final String? initialValue;
|
||||
final TextStyle? style;
|
||||
final InputDecoration? decoration;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
readOnly: true,
|
||||
controller: TextEditingController(text: initialValue),
|
||||
style: style,
|
||||
decoration: decoration ??
|
||||
const InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
contentPadding: kPv8,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:apidash/extensions/extensions.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'tabs.dart';
|
||||
import 'package:apidash/extensions/extensions.dart';
|
||||
|
||||
class RequestPane extends StatefulWidget {
|
||||
class RequestPane extends StatefulHookWidget {
|
||||
const RequestPane({
|
||||
super.key,
|
||||
required this.selectedId,
|
||||
@ -13,6 +14,7 @@ class RequestPane extends StatefulWidget {
|
||||
this.onTapTabBar,
|
||||
required this.children,
|
||||
this.showIndicators = const [false, false, false],
|
||||
this.showViewCodeButton,
|
||||
});
|
||||
|
||||
final String? selectedId;
|
||||
@ -22,6 +24,7 @@ class RequestPane extends StatefulWidget {
|
||||
final void Function(int)? onTapTabBar;
|
||||
final List<Widget> children;
|
||||
final List<bool> showIndicators;
|
||||
final bool? showViewCodeButton;
|
||||
|
||||
@override
|
||||
State<RequestPane> createState() => _RequestPaneState();
|
||||
@ -29,28 +32,19 @@ class RequestPane extends StatefulWidget {
|
||||
|
||||
class _RequestPaneState extends State<RequestPane>
|
||||
with TickerProviderStateMixin {
|
||||
late final TabController _controller;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = TabController(
|
||||
length: 3,
|
||||
animationDuration: kTabAnimationDuration,
|
||||
vsync: this,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final TabController controller = useTabController(
|
||||
initialLength: 3,
|
||||
vsync: this,
|
||||
);
|
||||
if (widget.tabIndex != null) {
|
||||
_controller.index = widget.tabIndex!;
|
||||
controller.index = widget.tabIndex!;
|
||||
}
|
||||
return Column(
|
||||
children: [
|
||||
context.isMediumWindow
|
||||
? const SizedBox.shrink()
|
||||
: Padding(
|
||||
(widget.showViewCodeButton ?? !context.isMediumWindow)
|
||||
? Padding(
|
||||
padding: kP8,
|
||||
child: SizedBox(
|
||||
height: kHeaderHeight,
|
||||
@ -76,10 +70,11 @@ class _RequestPaneState extends State<RequestPane>
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
TabBar(
|
||||
key: Key(widget.selectedId!),
|
||||
controller: _controller,
|
||||
controller: controller,
|
||||
overlayColor: kColorTransparentState,
|
||||
labelPadding: kPh2,
|
||||
onTap: widget.onTapTabBar,
|
||||
@ -101,7 +96,7 @@ class _RequestPaneState extends State<RequestPane>
|
||||
kVSpacer5,
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _controller,
|
||||
controller: controller,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: widget.children,
|
||||
),
|
||||
@ -109,10 +104,4 @@ class _RequestPaneState extends State<RequestPane>
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ class ResponsePaneHeader extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool showClearButton = onClearResponse != null;
|
||||
return Padding(
|
||||
padding: kPv8,
|
||||
child: SizedBox(
|
||||
@ -159,9 +160,11 @@ class ResponsePaneHeader extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
kHSpacer10,
|
||||
ClearResponseButton(
|
||||
showClearButton
|
||||
? ClearResponseButton(
|
||||
onPressed: onClearResponse,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
101
lib/widgets/table_request.dart
Normal file
101
lib/widgets/table_request.dart
Normal file
@ -0,0 +1,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:data_table_2/data_table_2.dart';
|
||||
import 'package:apidash/widgets/widgets.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
|
||||
class RequestDataTable extends StatelessWidget {
|
||||
const RequestDataTable({
|
||||
super.key,
|
||||
required this.rows,
|
||||
this.keyName,
|
||||
this.valueName,
|
||||
});
|
||||
|
||||
final Map<String, String> rows;
|
||||
final String? keyName;
|
||||
final String? valueName;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final clrScheme = Theme.of(context).colorScheme;
|
||||
|
||||
final List<DataColumn> columns = [
|
||||
DataColumn2(
|
||||
label: Text(keyName ?? kNameField),
|
||||
),
|
||||
const DataColumn2(
|
||||
label: Text('='),
|
||||
fixedWidth: 30,
|
||||
),
|
||||
DataColumn2(
|
||||
label: Text(valueName ?? kNameValue),
|
||||
),
|
||||
];
|
||||
|
||||
final fieldDecoration = InputDecoration(
|
||||
contentPadding: const EdgeInsets.only(bottom: 12),
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: clrScheme.primary.withOpacity(
|
||||
kHintOpacity,
|
||||
),
|
||||
),
|
||||
),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: clrScheme.surfaceContainerHighest,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final List<DataRow> dataRows = rows.entries
|
||||
.map<DataRow>(
|
||||
(MapEntry<String, String> entry) => DataRow(
|
||||
cells: <DataCell>[
|
||||
DataCell(
|
||||
ReadOnlyTextField(
|
||||
initialValue: entry.key,
|
||||
decoration: fieldDecoration,
|
||||
),
|
||||
),
|
||||
const DataCell(
|
||||
Text('='),
|
||||
),
|
||||
DataCell(
|
||||
ReadOnlyTextField(
|
||||
initialValue: entry.value,
|
||||
decoration: fieldDecoration,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
return Container(
|
||||
margin: kP10,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Theme(
|
||||
data: Theme.of(context)
|
||||
.copyWith(scrollbarTheme: kDataTableScrollbarTheme),
|
||||
child: DataTable2(
|
||||
columnSpacing: 12,
|
||||
dividerThickness: 0,
|
||||
horizontalMargin: 0,
|
||||
headingRowHeight: 0,
|
||||
dataRowHeight: kDataTableRowHeight,
|
||||
bottomMargin: kDataTableBottomPadding,
|
||||
isVerticalScrollBarVisible: true,
|
||||
columns: columns,
|
||||
rows: dataRows,
|
||||
),
|
||||
),
|
||||
),
|
||||
kVSpacer40,
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -32,3 +32,24 @@ class MethodBox extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StatusCode extends StatelessWidget {
|
||||
const StatusCode({super.key, required this.statusCode, this.style});
|
||||
final int statusCode;
|
||||
final TextStyle? style;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final brightness = Theme.of(context).brightness;
|
||||
final Color color =
|
||||
getResponseStatusCodeColor(statusCode, brightness: brightness);
|
||||
return Text(
|
||||
statusCode.toString(),
|
||||
style: style?.copyWith(color: color) ??
|
||||
Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontFamily: kCodeStyle.fontFamily,
|
||||
color: color,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ export 'button_discord.dart';
|
||||
export 'button_repo.dart';
|
||||
export 'button_save_download.dart';
|
||||
export 'button_send.dart';
|
||||
export 'card_history_request.dart';
|
||||
export 'card_request_details.dart';
|
||||
export 'card_sidebar_environment.dart';
|
||||
export 'card_sidebar_history.dart';
|
||||
@ -28,6 +29,7 @@ export 'field_cell.dart';
|
||||
export 'field_header.dart';
|
||||
export 'field_json_search.dart';
|
||||
export 'field_raw.dart';
|
||||
export 'field_read_only.dart';
|
||||
export 'field_url.dart';
|
||||
export 'intro_message.dart';
|
||||
export 'json_previewer.dart';
|
||||
@ -46,9 +48,9 @@ export 'splitview_drawer.dart';
|
||||
export 'splitview_dashboard.dart';
|
||||
export 'splitview_equal.dart';
|
||||
export 'splitview_history.dart';
|
||||
export 'suggestions_menu.dart';
|
||||
export 'tabbar_request_response.dart';
|
||||
export 'tables.dart';
|
||||
export 'table_map.dart';
|
||||
export 'table_request.dart';
|
||||
export 'tabs.dart';
|
||||
export 'texts.dart';
|
||||
export 'uint8_audio_player.dart';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/screens/home_page/editor_pane/details_card/code_pane.dart';
|
||||
import 'package:apidash/screens/common_widgets/common_widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import '../models/request_models.dart';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:apidash/codegen/codegen.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/screens/home_page/editor_pane/details_card/code_pane.dart';
|
||||
import 'package:apidash/screens/common_widgets/common_widgets.dart';
|
||||
import 'package:test/test.dart';
|
||||
import '../models/request_models.dart';
|
||||
|
||||
|
@ -1,12 +1,9 @@
|
||||
import 'dart:io';
|
||||
import 'package:spot/spot.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:apidash/providers/providers.dart';
|
||||
import 'package:apidash/screens/common_widgets/common_widgets.dart';
|
||||
import 'package:apidash/screens/dashboard.dart';
|
||||
import 'package:apidash/screens/envvar/environment_page.dart';
|
||||
import 'package:apidash/screens/home_page/collection_pane.dart';
|
||||
import 'package:apidash/screens/home_page/editor_pane/details_card/code_pane.dart';
|
||||
import 'package:apidash/screens/home_page/editor_pane/details_card/response_pane.dart';
|
||||
import 'package:apidash/screens/home_page/editor_pane/editor_default.dart';
|
||||
import 'package:apidash/screens/home_page/editor_pane/editor_pane.dart';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:apidash/widgets/tables.dart';
|
||||
import 'package:apidash/widgets/table_map.dart';
|
||||
|
||||
void main() {
|
||||
Map<String, String> mapInput = {
|
||||
|
Reference in New Issue
Block a user