diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 00000000..7e7e7f67 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/lib/consts.dart b/lib/consts.dart index e598db62..f8f9f97c 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -48,6 +48,7 @@ const kHintOpacity = 0.6; const kForegroundOpacity = 0.05; const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold); +const kTextStyleButtonSmall = TextStyle(fontSize: 12); const kFormDataButtonLabelTextStyle = TextStyle( fontSize: 12, fontWeight: FontWeight.w600, diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart index 1637f265..76866ab9 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_headers.dart @@ -54,7 +54,7 @@ class EditRequestHeadersState extends ConsumerState { columns: [ DaviColumn( name: 'Checkbox', - width: 36, + width: 30, cellBuilder: (_, row) { int idx = row.index; return CheckBox( @@ -72,6 +72,7 @@ class EditRequestHeadersState extends ConsumerState { ), DaviColumn( name: 'Header Name', + width: 70, grow: 1, cellBuilder: (_, row) { int idx = row.index; diff --git a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart index 18b17e58..736bf619 100644 --- a/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart +++ b/lib/screens/home_page/editor_pane/details_card/request_pane/request_params.dart @@ -55,7 +55,7 @@ class EditRequestURLParamsState extends ConsumerState { columns: [ DaviColumn( name: 'Checkbox', - width: 36, + width: 30, cellBuilder: (_, row) { int idx = row.index; @@ -74,6 +74,7 @@ class EditRequestURLParamsState extends ConsumerState { ), DaviColumn( name: 'URL Parameter', + width: 70, grow: 1, cellBuilder: (_, row) { int idx = row.index; diff --git a/lib/utils/ui_utils.dart b/lib/utils/ui_utils.dart index aeaf1b1a..3bf1fb98 100644 --- a/lib/utils/ui_utils.dart +++ b/lib/utils/ui_utils.dart @@ -59,3 +59,13 @@ Color getDarkModeColor(Color col) { kColorWhite, ); } + +double? getJsonPreviewerMaxRootNodeWidth(double w) { + if (w < 300) { + return 150; + } + if (w < 400) { + return 200; + } + return w - 150; +} diff --git a/lib/widgets/json_previewer.dart b/lib/widgets/json_previewer.dart index 49b1eb10..078a9721 100644 --- a/lib/widgets/json_previewer.dart +++ b/lib/widgets/json_previewer.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:url_launcher/url_launcher_string.dart'; import '../consts.dart'; +import '../utils/ui_utils.dart'; import "snackbars.dart"; import 'textfields.dart'; @@ -151,120 +152,151 @@ class _JsonPreviewerState extends State { store.expandAll(); } + @override + void didUpdateWidget(JsonPreviewer oldWidget) { + if (oldWidget.code != widget.code) { + store.buildNodes(widget.code, areAllCollapsed: true); + store.expandAll(); + } + } + @override Widget build(BuildContext context) { var sm = ScaffoldMessenger.of(context); return ChangeNotifierProvider.value( value: store, child: Consumer( - builder: (context, state, child) => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - onPressed: () async { - await _copy(kEncoder.convert(widget.code), sm); - }, - child: const Text('Copy'), - ), - TextButton( - onPressed: state.areAllExpanded() ? null : state.expandAll, - child: const Text('Expand All'), - ), - TextButton( - onPressed: state.areAllCollapsed() ? null : state.collapseAll, - child: const Text('Collapse All'), - ), - ], - ), - Expanded( - child: JsonDataExplorer( - nodes: state.displayNodes, - itemScrollController: itemScrollController, - itemSpacing: 4, - rootInformationBuilder: (context, node) => - rootInfoBox(context, node), - collapsableToggleBuilder: (context, node) => AnimatedRotation( - turns: node.isCollapsed ? -0.25 : 0, - duration: const Duration(milliseconds: 300), - child: const Icon(Icons.arrow_drop_down), - ), - trailingBuilder: (context, node) => node.isFocused - ? Padding( - padding: const EdgeInsets.only(right: 12), - child: IconButton( - padding: EdgeInsets.zero, - constraints: const BoxConstraints(maxHeight: 18), - icon: const Icon( - Icons.copy, - size: 18, - ), - onPressed: () async { - await _copy(kEncoder.convert(toJson(node)), sm); - }, - ), - ) - : const SizedBox(), - valueStyleBuilder: (value, style) => - valueStyleOverride(context, value, style), - theme: (Theme.of(context).brightness == Brightness.light) - ? dataExplorerThemeLight - : dataExplorerThemeDark, - ), - ), - Container( - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - border: Border.all( - color: Theme.of(context).colorScheme.surfaceVariant), - borderRadius: kBorderRadius8, - ), - child: Row( + builder: (context, state, child) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + var maxRootNodeWidth = + getJsonPreviewerMaxRootNodeWidth(constraints.maxWidth); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.symmetric(horizontal: 8.0), - child: Icon( - Icons.search, - size: 18, - ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () async { + await _copy(kEncoder.convert(widget.code), sm); + }, + child: const Text( + 'Copy', + style: kTextStyleButtonSmall, + ), + ), + TextButton( + onPressed: + state.areAllExpanded() ? null : state.expandAll, + child: const Text( + 'Expand All', + style: kTextStyleButtonSmall, + ), + ), + TextButton( + onPressed: + state.areAllCollapsed() ? null : state.collapseAll, + child: const Text( + 'Collapse All', + style: kTextStyleButtonSmall, + ), + ), + ], ), Expanded( - child: JsonSearchField( - controller: searchController, - onChanged: (term) => state.search(term), + child: JsonDataExplorer( + nodes: state.displayNodes, + itemScrollController: itemScrollController, + itemSpacing: 4, + rootInformationBuilder: (context, node) => + rootInfoBox(context, node), + collapsableToggleBuilder: (context, node) => + AnimatedRotation( + turns: node.isCollapsed ? -0.25 : 0, + duration: const Duration(milliseconds: 300), + child: const Icon(Icons.arrow_drop_down), + ), + trailingBuilder: (context, node) => node.isFocused + ? Padding( + padding: const EdgeInsets.only(right: 12), + child: IconButton( + padding: EdgeInsets.zero, + constraints: + const BoxConstraints(maxHeight: 18), + icon: const Icon( + Icons.copy, + size: 18, + ), + onPressed: () async { + await _copy( + kEncoder.convert(toJson(node)), sm); + }, + ), + ) + : const SizedBox(), + valueStyleBuilder: (value, style) => + valueStyleOverride(context, value, style), + theme: (Theme.of(context).brightness == Brightness.light) + ? dataExplorerThemeLight + : dataExplorerThemeDark, + maxRootNodeWidth: maxRootNodeWidth, ), ), - const SizedBox( - width: 8, + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + border: Border.all( + color: Theme.of(context).colorScheme.surfaceVariant), + borderRadius: kBorderRadius8, + ), + child: Row( + children: [ + const Padding( + padding: EdgeInsets.symmetric(horizontal: 8.0), + child: Icon( + Icons.search, + size: 18, + ), + ), + Expanded( + child: JsonSearchField( + controller: searchController, + onChanged: (term) => state.search(term), + ), + ), + const SizedBox( + width: 8, + ), + if (state.searchResults.isNotEmpty) + Text(_searchFocusText(), + style: Theme.of(context).textTheme.bodySmall), + if (state.searchResults.isNotEmpty) + IconButton( + visualDensity: VisualDensity.compact, + onPressed: () { + store.focusPreviousSearchResult(); + _scrollToSearchMatch(); + }, + icon: const Icon(Icons.arrow_drop_up), + ), + if (state.searchResults.isNotEmpty) + IconButton( + visualDensity: VisualDensity.compact, + onPressed: () { + store.focusNextSearchResult(); + _scrollToSearchMatch(); + }, + icon: const Icon(Icons.arrow_drop_down), + ), + ], + ), ), - if (state.searchResults.isNotEmpty) - Text(_searchFocusText(), - style: Theme.of(context).textTheme.bodySmall), - if (state.searchResults.isNotEmpty) - IconButton( - visualDensity: VisualDensity.compact, - onPressed: () { - store.focusPreviousSearchResult(); - _scrollToSearchMatch(); - }, - icon: const Icon(Icons.arrow_drop_up), - ), - if (state.searchResults.isNotEmpty) - IconButton( - visualDensity: VisualDensity.compact, - onPressed: () { - store.focusNextSearchResult(); - _scrollToSearchMatch(); - }, - icon: const Icon(Icons.arrow_drop_down), - ), ], - ), - ), - ], - ), + ); + }, + ); + }, ), ); } diff --git a/lib/widgets/response_widgets.dart b/lib/widgets/response_widgets.dart index 680041c0..c45a44f7 100644 --- a/lib/widgets/response_widgets.dart +++ b/lib/widgets/response_widgets.dart @@ -397,6 +397,13 @@ class _BodySuccessState extends State { (widget.options == kRawBodyViewOptions) ? const SizedBox() : SegmentedButton( + style: const ButtonStyle( + padding: MaterialStatePropertyAll( + EdgeInsets.symmetric( + horizontal: 8, + ), + ), + ), selectedIcon: Icon(currentSeg.icon), segments: widget.options .map>( @@ -418,7 +425,7 @@ class _BodySuccessState extends State { const Spacer(), kCodeRawBodyViewOptions.contains(currentSeg) ? CopyButton( - toCopy: widget.body, + toCopy: widget.formattedBody ?? widget.body, showLabel: showLabel, ) : const SizedBox(), @@ -474,7 +481,7 @@ class _BodySuccessState extends State { decoration: textContainerdecoration, child: SingleChildScrollView( child: SelectableText( - widget.body, + widget.formattedBody ?? widget.body, style: kCodeStyle, ), ), diff --git a/pubspec.lock b/pubspec.lock index 55fc4e74..ef1e25a4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -281,6 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" + url: "https://pub.dev" + source: hosted + version: "6.1.1" fixnum: dependency: transitive description: @@ -366,6 +374,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.18+2" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + url: "https://pub.dev" + source: hosted + version: "2.0.17" flutter_riverpod: dependency: "direct main" description: @@ -548,11 +564,11 @@ packages: dependency: "direct main" description: path: "." - ref: HEAD - resolved-ref: "9e279ee9862c4fc4050dbcb5074529b22e67a7c3" + ref: "9fa58d7b51e65174ab11cbcae17bba88a4194dde" + resolved-ref: "9fa58d7b51e65174ab11cbcae17bba88a4194dde" url: "https://github.com/foss42/json_data_explorer.git" source: git - version: "0.1.1" + version: "0.1.2" json_serializable: dependency: "direct dev" description: @@ -1304,5 +1320,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.2.3 <4.0.0" flutter: ">=3.16.0" diff --git a/pubspec.yaml b/pubspec.yaml index d6a1a718..b554b38e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,7 +47,7 @@ dependencies: json_data_explorer: git: url: https://github.com/foss42/json_data_explorer.git - version: ^0.1.1 + ref: 9fa58d7b51e65174ab11cbcae17bba88a4194dde scrollable_positioned_list: ^0.2.3 file_picker: ^6.1.1 flutter_svg: ^2.0.9