mirror of
https://github.com/foss42/apidash.git
synced 2025-06-27 19:07:40 +08:00
Merge branch 'add-feature-header-suggestions' of https://github.com/DenserMeerkat/apidash into add-feature-header-suggestions
This commit is contained in:
@ -312,6 +312,10 @@ const kCodeRawBodyViewOptions = [ResponseBodyView.code, ResponseBodyView.raw];
|
||||
const kPreviewBodyViewOptions = [
|
||||
ResponseBodyView.preview,
|
||||
];
|
||||
const kPreviewRawBodyViewOptions = [
|
||||
ResponseBodyView.preview,
|
||||
ResponseBodyView.raw
|
||||
];
|
||||
const kPreviewCodeRawBodyViewOptions = [
|
||||
ResponseBodyView.preview,
|
||||
ResponseBodyView.code,
|
||||
@ -322,7 +326,7 @@ const Map<String, Map<String, List<ResponseBodyView>>>
|
||||
kResponseBodyViewOptions = {
|
||||
kTypeApplication: {
|
||||
kSubTypeDefaultViewOptions: kNoRawBodyViewOptions,
|
||||
kSubTypeJson: kCodeRawBodyViewOptions,
|
||||
kSubTypeJson: kPreviewRawBodyViewOptions,
|
||||
kSubTypeOctetStream: kNoBodyViewOptions,
|
||||
kSubTypePdf: kPreviewBodyViewOptions,
|
||||
kSubTypeSql: kCodeRawBodyViewOptions,
|
||||
|
403
lib/widgets/json_previewer.dart
Normal file
403
lib/widgets/json_previewer.dart
Normal file
@ -0,0 +1,403 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:json_data_explorer/json_data_explorer.dart';
|
||||
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 "snackbars.dart";
|
||||
import 'textfields.dart';
|
||||
|
||||
class JsonPreviewerColor {
|
||||
const JsonPreviewerColor._();
|
||||
|
||||
static const Color lightRootInfoBox = Color(0x80E1E1E1);
|
||||
static const Color lightRootKeyText = Colors.black;
|
||||
static const Color lightPropertyKeyText = Colors.black;
|
||||
static const Color lightKeySearchHighlightText = Colors.black;
|
||||
static const Color lightKeySearchHighlightBackground = Color(0xFFFFEDAD);
|
||||
static const Color lightFocusedKeySearchHighlightText = Colors.black;
|
||||
static const Color lightFocusedKeySearchHighlightBackground =
|
||||
Color(0xFFF29D0B);
|
||||
static const Color lightValueText = Color(0xffc41a16);
|
||||
static const Color lightValueSearchHighlightText = Color(0xffc41a16);
|
||||
static const Color lightValueNum = Color(0xff3F6E74);
|
||||
static const Color lightValueBool = Color(0xff1c00cf);
|
||||
static const Color lightValueSearchHighlightBackground = Color(0xFFFFEDAD);
|
||||
static const Color lightFocusedValueSearchHighlightText = Colors.black;
|
||||
static const Color lightFocusedValueSearchHighlightBackground =
|
||||
Color(0xFFF29D0B);
|
||||
static const Color lightIndentationLineColor =
|
||||
Color.fromARGB(255, 213, 213, 213);
|
||||
static const Color lightHighlightColor = Color(0xFFF1F1F1);
|
||||
|
||||
// Dark colors
|
||||
static const Color darkRootInfoBox = Color.fromARGB(255, 83, 13, 19);
|
||||
static const Color darkRootKeyText = Color(0xffd6deeb);
|
||||
static const Color darkPropertyKeyText = Color(0xffd6deeb);
|
||||
static const Color darkKeySearchHighlightText = Color(0xffd6deeb);
|
||||
static const Color darkKeySearchHighlightBackground = Color(0xff9b703f);
|
||||
static const Color darkFocusedKeySearchHighlightText = Color(0xffd6deeb);
|
||||
static const Color darkFocusedKeySearchHighlightBackground =
|
||||
Color(0xffc41a16);
|
||||
static const Color darkValueText = Color(0xffecc48d);
|
||||
static const Color darkValueSearchHighlightText = Color(0xffecc48d);
|
||||
static const Color darkValueNum = Color(0xffaddb67);
|
||||
static const Color darkValueBool = Color(0xff82aaff);
|
||||
static const Color darkValueSearchHighlightBackground = Color(0xff9b703f);
|
||||
static const Color darkFocusedValueSearchHighlightText = Color(0xffd6deeb);
|
||||
static const Color darkFocusedValueSearchHighlightBackground =
|
||||
Color(0xffc41a16);
|
||||
static const Color darkIndentationLineColor =
|
||||
Color.fromARGB(255, 119, 119, 119);
|
||||
static const Color darkHighlightColor = Color.fromARGB(255, 55, 55, 55);
|
||||
}
|
||||
|
||||
final dataExplorerThemeLight = DataExplorerTheme(
|
||||
rootKeyTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightRootKeyText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
propertyKeyTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightPropertyKeyText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
keySearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightKeySearchHighlightText,
|
||||
backgroundColor: JsonPreviewerColor.lightKeySearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
focusedKeySearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightFocusedKeySearchHighlightText,
|
||||
backgroundColor:
|
||||
JsonPreviewerColor.lightFocusedKeySearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
valueTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightValueText,
|
||||
),
|
||||
valueSearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightValueSearchHighlightText,
|
||||
backgroundColor: JsonPreviewerColor.lightValueSearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
focusedValueSearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.lightFocusedValueSearchHighlightText,
|
||||
backgroundColor:
|
||||
JsonPreviewerColor.lightFocusedValueSearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
indentationLineColor: JsonPreviewerColor.lightIndentationLineColor,
|
||||
highlightColor: JsonPreviewerColor.lightHighlightColor,
|
||||
);
|
||||
|
||||
final dataExplorerThemeDark = DataExplorerTheme(
|
||||
rootKeyTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkRootKeyText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
propertyKeyTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkPropertyKeyText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
keySearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkKeySearchHighlightText,
|
||||
backgroundColor: JsonPreviewerColor.darkKeySearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
focusedKeySearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkFocusedKeySearchHighlightText,
|
||||
backgroundColor: JsonPreviewerColor.darkFocusedKeySearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
valueTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkValueText,
|
||||
),
|
||||
valueSearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkValueSearchHighlightText,
|
||||
backgroundColor: JsonPreviewerColor.darkValueSearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
focusedValueSearchHighlightTextStyle: kCodeStyle.copyWith(
|
||||
color: JsonPreviewerColor.darkFocusedValueSearchHighlightText,
|
||||
backgroundColor:
|
||||
JsonPreviewerColor.darkFocusedValueSearchHighlightBackground,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
indentationLineColor: JsonPreviewerColor.darkIndentationLineColor,
|
||||
highlightColor: JsonPreviewerColor.darkHighlightColor,
|
||||
);
|
||||
|
||||
class JsonPreviewer extends StatefulWidget {
|
||||
const JsonPreviewer({
|
||||
super.key,
|
||||
required this.code,
|
||||
});
|
||||
final String code;
|
||||
|
||||
@override
|
||||
State<JsonPreviewer> createState() => _JsonPreviewerState();
|
||||
}
|
||||
|
||||
class _JsonPreviewerState extends State<JsonPreviewer> {
|
||||
final searchController = TextEditingController();
|
||||
final itemScrollController = ItemScrollController();
|
||||
final DataExplorerStore store = DataExplorerStore();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
store.buildNodes(jsonDecode(widget.code), areAllCollapsed: true);
|
||||
store.expandAll();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var sm = ScaffoldMessenger.of(context);
|
||||
return ChangeNotifierProvider.value(
|
||||
value: store,
|
||||
child: Consumer<DataExplorerStore>(
|
||||
builder: (context, state, child) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await _copy(kEncoder.convert(jsonDecode(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(
|
||||
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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _copy(String text, ScaffoldMessengerState sm) async {
|
||||
String msg;
|
||||
try {
|
||||
await Clipboard.setData(ClipboardData(text: text));
|
||||
msg = "Copied";
|
||||
} catch (e) {
|
||||
msg = "An error occurred";
|
||||
}
|
||||
sm.hideCurrentSnackBar();
|
||||
sm.showSnackBar(getSnackBar(msg));
|
||||
}
|
||||
|
||||
PropertyOverrides valueStyleOverride(
|
||||
BuildContext context,
|
||||
dynamic value,
|
||||
TextStyle style,
|
||||
) {
|
||||
TextStyle newStyle = style;
|
||||
bool isUrl = false;
|
||||
if (value.runtimeType.toString() == "num" ||
|
||||
value.runtimeType.toString() == "double" ||
|
||||
value.runtimeType.toString() == "int") {
|
||||
newStyle = style.copyWith(
|
||||
color: (Theme.of(context).brightness == Brightness.light)
|
||||
? JsonPreviewerColor.lightValueNum
|
||||
: JsonPreviewerColor.darkValueNum,
|
||||
);
|
||||
} else if (value.runtimeType.toString() == "bool") {
|
||||
newStyle = style.copyWith(
|
||||
color: (Theme.of(context).brightness == Brightness.light)
|
||||
? JsonPreviewerColor.lightValueBool
|
||||
: JsonPreviewerColor.darkValueBool,
|
||||
);
|
||||
} else {
|
||||
isUrl = _valueIsUrl(value);
|
||||
if (isUrl) {
|
||||
newStyle = style.copyWith(
|
||||
decoration: TextDecoration.underline,
|
||||
decorationColor: (Theme.of(context).brightness == Brightness.light)
|
||||
? JsonPreviewerColor.lightValueText
|
||||
: JsonPreviewerColor.darkValueText,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return PropertyOverrides(
|
||||
style: newStyle,
|
||||
onTap: isUrl ? () => _launchUrl(value as String) : null,
|
||||
);
|
||||
}
|
||||
|
||||
DecoratedBox rootInfoBox(BuildContext context, NodeViewModelState node) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: (Theme.of(context).brightness == Brightness.light)
|
||||
? JsonPreviewerColor.lightRootInfoBox
|
||||
: JsonPreviewerColor.darkRootInfoBox,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(2)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4,
|
||||
vertical: 2,
|
||||
),
|
||||
child: Text(
|
||||
node.isClass ? '{${node.childrenCount}}' : '[${node.childrenCount}]',
|
||||
style: kCodeStyle,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _searchFocusText() =>
|
||||
'${store.focusedSearchResultIndex + 1} of ${store.searchResults.length}';
|
||||
|
||||
void _scrollToSearchMatch() {
|
||||
final index = store.displayNodes.indexOf(store.focusedSearchResult.node);
|
||||
if (index != -1) {
|
||||
itemScrollController.scrollTo(
|
||||
index: index,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOutCubic,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool _valueIsUrl(dynamic value) {
|
||||
if (value is String) {
|
||||
return Uri.tryParse(value)?.hasAbsolutePath ?? false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Future _launchUrl(String url) {
|
||||
return launchUrlString(url);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
searchController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
dynamic toJson(
|
||||
NodeViewModelState node,
|
||||
) {
|
||||
dynamic res;
|
||||
if (node.isRoot) {
|
||||
if (node.isClass) {
|
||||
res = {};
|
||||
for (var i in node.children) {
|
||||
res.addAll(toJson(i));
|
||||
}
|
||||
}
|
||||
if (node.isArray) {
|
||||
res = [];
|
||||
for (var i in node.children) {
|
||||
res.add(toJson(i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = node.value;
|
||||
}
|
||||
|
||||
if (node.parent != null && node.parent!.isArray) {
|
||||
return res;
|
||||
} else {
|
||||
return {node.key: res};
|
||||
}
|
||||
}
|
@ -4,18 +4,20 @@ import 'error_message.dart';
|
||||
import 'package:apidash/consts.dart';
|
||||
import 'package:printing/printing.dart';
|
||||
import 'uint8_audio_player.dart';
|
||||
|
||||
import 'json_previewer.dart';
|
||||
|
||||
class Previewer extends StatefulWidget {
|
||||
const Previewer({
|
||||
super.key,
|
||||
required this.bytes,
|
||||
required this.body,
|
||||
this.type,
|
||||
this.subtype,
|
||||
this.hasRaw = false,
|
||||
});
|
||||
|
||||
final Uint8List bytes;
|
||||
final String body;
|
||||
final String? type;
|
||||
final String? subtype;
|
||||
final bool hasRaw;
|
||||
@ -27,6 +29,11 @@ class Previewer extends StatefulWidget {
|
||||
class _PreviewerState extends State<Previewer> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.type == kTypeApplication && widget.subtype == kSubTypeJson) {
|
||||
return JsonPreviewer(
|
||||
code: widget.body,
|
||||
);
|
||||
}
|
||||
if (widget.type == kTypeImage) {
|
||||
return Image.memory(
|
||||
widget.bytes,
|
||||
|
@ -453,14 +453,20 @@ class _BodySuccessState extends State<BodySuccess> {
|
||||
visible: currentSeg == ResponseBodyView.preview ||
|
||||
currentSeg == ResponseBodyView.none,
|
||||
child: Expanded(
|
||||
child: Container(
|
||||
width: double.maxFinite,
|
||||
padding: kP8,
|
||||
decoration: textContainerdecoration,
|
||||
child: Previewer(
|
||||
bytes: widget.bytes,
|
||||
body: widget.body,
|
||||
type: widget.mediaType.type,
|
||||
subtype: widget.mediaType.subtype,
|
||||
hasRaw: widget.options.contains(ResponseBodyView.raw),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.formattedBody != null)
|
||||
Visibility(
|
||||
visible: currentSeg == ResponseBodyView.code,
|
||||
|
@ -97,3 +97,25 @@ class _CellFieldState extends State<CellField> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class JsonSearchField extends StatelessWidget {
|
||||
const JsonSearchField({super.key, this.onChanged, this.controller});
|
||||
|
||||
final void Function(String)? onChanged;
|
||||
final TextEditingController? controller;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextField(
|
||||
controller: controller,
|
||||
onChanged: onChanged,
|
||||
style: kCodeStyle,
|
||||
cursorHeight: 18,
|
||||
decoration: const InputDecoration(
|
||||
isDense: true,
|
||||
border: InputBorder.none,
|
||||
hintText: 'Search..',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -19,3 +19,4 @@ export 'snackbars.dart';
|
||||
export 'markdown.dart';
|
||||
export 'uint8_audio_player.dart';
|
||||
export 'tabs.dart';
|
||||
export 'json_previewer.dart';
|
||||
|
32
pubspec.lock
32
pubspec.lock
@ -520,6 +520,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.8.1"
|
||||
json_data_explorer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_data_explorer
|
||||
sha256: "303a00037b23963fd01be1b2dc509f14e9db2a40f852b0ce042d7635c22fd154"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -656,6 +664,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: nested
|
||||
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
node_preamble:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -816,6 +832,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.11.0"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: provider
|
||||
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.5"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -864,6 +888,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.8"
|
||||
scrollable_positioned_list:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: scrollable_positioned_list
|
||||
sha256: "9566352ab9ba05794ee6c8864f154afba5d36c5637d0e3e32c615ba4ceb92772"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.3"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -42,6 +42,9 @@ dependencies:
|
||||
printing: ^5.11.0
|
||||
package_info_plus: ^4.1.0
|
||||
flutter_typeahead: ^4.8.0
|
||||
provider: ^6.0.5
|
||||
json_data_explorer: ^0.1.0
|
||||
scrollable_positioned_list: ^0.2.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -13,7 +13,12 @@ void main() {
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(type: 'application', subtype: 'pdf', bytes: bytes1),
|
||||
body: Previewer(
|
||||
type: 'application',
|
||||
subtype: 'pdf',
|
||||
bytes: bytes1,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -30,7 +35,12 @@ void main() {
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(type: 'audio', subtype: 'mpeg', bytes: bytes1),
|
||||
body: Previewer(
|
||||
type: 'audio',
|
||||
subtype: 'mpeg',
|
||||
bytes: bytes1,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -43,7 +53,12 @@ void main() {
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(type: 'video', subtype: 'H264', bytes: bytes1),
|
||||
body: Previewer(
|
||||
type: 'video',
|
||||
subtype: 'H264',
|
||||
bytes: bytes1,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -58,7 +73,12 @@ void main() {
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(type: 'model', subtype: 'step+xml', bytes: bytes1),
|
||||
body: Previewer(
|
||||
type: 'model',
|
||||
subtype: 'step+xml',
|
||||
bytes: bytes1,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -74,8 +94,12 @@ void main() {
|
||||
MaterialApp(
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body:
|
||||
Previewer(type: 'image', subtype: 'jpeg', bytes: kBodyBytesJpeg),
|
||||
body: Previewer(
|
||||
type: 'image',
|
||||
subtype: 'jpeg',
|
||||
bytes: kBodyBytesJpeg,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -113,7 +137,11 @@ void main() {
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(
|
||||
type: 'image', subtype: 'jpeg', bytes: bytesJpegCorrupt),
|
||||
type: 'image',
|
||||
subtype: 'jpeg',
|
||||
bytes: bytesJpegCorrupt,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -130,7 +158,11 @@ void main() {
|
||||
title: 'Previewer',
|
||||
home: Scaffold(
|
||||
body: Previewer(
|
||||
type: 'audio', subtype: 'mpeg', bytes: bytesAudioCorrupt),
|
||||
type: 'audio',
|
||||
subtype: 'mpeg',
|
||||
bytes: bytesAudioCorrupt,
|
||||
body: "",
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
Reference in New Issue
Block a user