diff --git a/lib/providers/ui_providers.dart b/lib/providers/ui_providers.dart index 9b6cc3e0..0478b040 100644 --- a/lib/providers/ui_providers.dart +++ b/lib/providers/ui_providers.dart @@ -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); diff --git a/lib/screens/home_page/editor_pane/details_card/code_pane.dart b/lib/screens/common_widgets/code_pane.dart similarity index 79% rename from lib/screens/home_page/editor_pane/details_card/code_pane.dart rename to lib/screens/common_widgets/code_pane.dart index f61c10a6..1da84542 100644 --- a/lib/screens/home_page/editor_pane/details_card/code_pane.dart +++ b/lib/screens/common_widgets/code_pane.dart @@ -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)); diff --git a/lib/screens/common_widgets/common_widgets.dart b/lib/screens/common_widgets/common_widgets.dart index 6c08887a..02a1f583 100644 --- a/lib/screens/common_widgets/common_widgets.dart +++ b/lib/screens/common_widgets/common_widgets.dart @@ -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'; diff --git a/lib/screens/history/details_pane/his_request_pane.dart b/lib/screens/history/details_pane/his_request_pane.dart new file mode 100644 index 00000000..6378a871 --- /dev/null +++ b/lib/screens/history/details_pane/his_request_pane.dart @@ -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(), + ], + ); + } +} diff --git a/lib/screens/history/details_pane/his_response_pane.dart b/lib/screens/history/details_pane/his_response_pane.dart new file mode 100644 index 00000000..f90390cb --- /dev/null +++ b/lib/screens/history/details_pane/his_response_pane.dart @@ -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"); + } +} diff --git a/lib/screens/history/details_pane/url_card.dart b/lib/screens/history/details_pane/url_card.dart index af5d4a41..cb8ec0da 100644 --- a/lib/screens/history/details_pane/url_card.dart +++ b/lib/screens/history/details_pane/url_card.dart @@ -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, ), diff --git a/lib/screens/history/history_details.dart b/lib/screens/history/history_details.dart index cee748ba..7498fa5f 100644 --- a/lib/screens/history/history_details.dart +++ b/lib/screens/history/history_details.dart @@ -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( - children: [ - Padding( - padding: kP4, - child: HistoryURLCard( - method: metaData!.method, url: metaData.url)), - kVSpacer10, - RequestResponseTabbar( - controller: controller, - ), - ], + ? LayoutBuilder( + builder: (context, constraints) { + final isCompact = constraints.maxWidth < kMediumWindowWidth; + return Column( + children: [ + kVSpacer5, + Padding( + padding: kPh4, + child: HistoryURLCard( + 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(); } } diff --git a/lib/screens/history/history_page.dart b/lib/screens/history/history_page.dart index 69f105ab..0f288fb7 100644 --- a/lib/screens/history/history_page.dart +++ b/lib/screens/history/history_page.dart @@ -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) => diff --git a/lib/screens/history/history_pane.dart b/lib/screens/history/history_pane.dart index 00620f92..be7e36d7 100644 --- a/lib/screens/history/history_pane.dart +++ b/lib/screens/history/history_pane.dart @@ -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( - 'No history', - style: TextStyle(color: Colors.grey), + const Center( + child: Text( + 'No history', + style: TextStyle(color: Colors.grey), + ), ) ], ), diff --git a/lib/screens/history/history_requests.dart b/lib/screens/history/history_requests.dart index 1a80c2be..f0bc10cf 100644 --- a/lib/screens/history/history_requests.dart +++ b/lib/screens/history/history_requests.dart @@ -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(), + ), + )) + ], ); } } diff --git a/lib/screens/home_page/editor_pane/details_card/details_card.dart b/lib/screens/home_page/editor_pane/details_card/details_card.dart index e14c139c..739f7475 100644 --- a/lib/screens/home_page/editor_pane/details_card/details_card.dart +++ b/lib/screens/home_page/editor_pane/details_card/details_card.dart @@ -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}); diff --git a/lib/screens/mobile/requests_page/requests_page.dart b/lib/screens/mobile/requests_page/requests_page.dart index 86d4d70d..4164356c 100644 --- a/lib/screens/mobile/requests_page/requests_page.dart +++ b/lib/screens/mobile/requests_page/requests_page.dart @@ -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'; diff --git a/lib/utils/convert_utils.dart b/lib/utils/convert_utils.dart index 735ace25..c772134e 100644 --- a/lib/utils/convert_utils.dart +++ b/lib/utils/convert_utils.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 ""; diff --git a/lib/utils/history_utils.dart b/lib/utils/history_utils.dart index de04cd24..acbea853 100644 --- a/lib/utils/history_utils.dart +++ b/lib/utils/history_utils.dart @@ -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; diff --git a/lib/widgets/card_history_request.dart b/lib/widgets/card_history_request.dart new file mode 100644 index 00000000..a76e477c --- /dev/null +++ b/lib/widgets/card_history_request.dart @@ -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), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/widgets/field_read_only.dart b/lib/widgets/field_read_only.dart new file mode 100644 index 00000000..abdb0b4e --- /dev/null +++ b/lib/widgets/field_read_only.dart @@ -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, + ), + ); + } +} diff --git a/lib/widgets/request_widgets.dart b/lib/widgets/request_widgets.dart index 368bba5f..1e7b7ccf 100644 --- a/lib/widgets/request_widgets.dart +++ b/lib/widgets/request_widgets.dart @@ -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(); - } } diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index ce07c100..0df9343b 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -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( - onPressed: onClearResponse, - ) + showClearButton + ? ClearResponseButton( + onPressed: onClearResponse, + ) + : const SizedBox.shrink(), ], ), ), diff --git a/lib/widgets/tables.dart b/lib/widgets/table_map.dart similarity index 100% rename from lib/widgets/tables.dart rename to lib/widgets/table_map.dart diff --git a/lib/widgets/table_request.dart b/lib/widgets/table_request.dart new file mode 100644 index 00000000..bdde7c47 --- /dev/null +++ b/lib/widgets/table_request.dart @@ -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, + ], + ), + ); + } +} diff --git a/lib/widgets/texts.dart b/lib/widgets/texts.dart index f2cf5c92..71753bfc 100644 --- a/lib/widgets/texts.dart +++ b/lib/widgets/texts.dart @@ -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, + ), + ); + } +} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index b80b6cf9..9f0323aa 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -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'; diff --git a/test/codegen/csharp_rest_sharp_codgen_test.dart b/test/codegen/csharp_rest_sharp_codgen_test.dart index 6522cbee..df16f928 100644 --- a/test/codegen/csharp_rest_sharp_codgen_test.dart +++ b/test/codegen/csharp_rest_sharp_codgen_test.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'; diff --git a/test/codegen/go_http_codegen_test.dart b/test/codegen/go_http_codegen_test.dart index 08492cf1..89e4c010 100644 --- a/test/codegen/go_http_codegen_test.dart +++ b/test/codegen/go_http_codegen_test.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'; diff --git a/test/providers/ui_providers_test.dart b/test/providers/ui_providers_test.dart index 6ebf7745..5854f768 100644 --- a/test/providers/ui_providers_test.dart +++ b/test/providers/ui_providers_test.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'; diff --git a/test/widgets/tables_test.dart b/test/widgets/tables_test.dart index 70102cfe..46b4bc1a 100644 --- a/test/widgets/tables_test.dart +++ b/test/widgets/tables_test.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 = {