2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

Merge pull request #89 from inventree/label-printing

Label printing
This commit is contained in:
Oliver 2022-03-26 11:32:17 +11:00 committed by GitHub
commit 0b3e716827
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 388 additions and 101 deletions

View File

@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 30
compileSdkVersion 31
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@ -49,7 +49,7 @@ android {
defaultConfig {
applicationId "inventree.inventree_app"
minSdkVersion 25
targetSdkVersion 30
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

View File

@ -1,6 +1,11 @@
## InvenTree App Release Notes
---
### x.x.x - March 2022
---
- Enables printing of stock item labels
### 0.5.6 - January 2022
---

View File

@ -17,6 +17,7 @@ import "package:flutter_cache_manager/flutter_cache_manager.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/l10.dart";
import "package:inventree/inventree/sentry.dart";
import "package:inventree/inventree/model.dart";
import "package:inventree/user_profile.dart";
import "package:inventree/widget/snacks.dart";
import "package:path_provider/path_provider.dart";
@ -227,6 +228,39 @@ class InvenTreeAPI {
int get apiVersion => _apiVersion;
// Are plugins enabled on the server?
bool _pluginsEnabled = false;
// True plugin support requires API v34 or newer
// Returns True only if the server API version is new enough, and plugins are enabled
bool pluginsEnabled() => apiVersion >= 34 && _pluginsEnabled;
// Cached list of plugins (refreshed when we connect to the server)
List<InvenTreePlugin> _plugins = [];
// Return a list of plugins enabled on the server
// Can optionally filter by a particular 'mixin' type
List<InvenTreePlugin> getPlugins({String mixin = ""}) {
List<InvenTreePlugin> plugins = [];
for (var plugin in _plugins) {
// Do we wish to filter by a particular mixin?
if (mixin.isNotEmpty) {
if (!plugin.supportsMixin(mixin)) {
continue;
}
}
plugins.add(plugin);
}
// Return list of matching plugins
return plugins;
}
// Test if the provided plugin mixin is supported by any active plugins
bool supportsMixin(String mixin) => getPlugins(mixin: mixin).isNotEmpty;
// Getter for server version information
String get version => _version;
@ -294,6 +328,9 @@ class InvenTreeAPI {
_BASE_URL = address;
// Clear the list of available plugins
_plugins.clear();
print("Connecting to ${apiUrl} -> username=${username}");
APIResponse response;
@ -324,6 +361,7 @@ class InvenTreeAPI {
// Default API version is 1 if not provided
_apiVersion = (data["apiVersion"] ?? 1) as int;
_pluginsEnabled = (data["plugins_enabled"] ?? false) as bool;
if (_apiVersion < _minApiVersion) {
@ -338,7 +376,7 @@ class InvenTreeAPI {
showServerError(
L10().serverOld,
message
message,
);
return false;
@ -387,8 +425,11 @@ class InvenTreeAPI {
_token = (data["token"] ?? "") as String;
print("Received token - $_token");
// Request user role information
await getUserRoles();
// Request user role information (async)
getUserRoles();
// Request plugin information (async)
getPluginInformation();
// Ok, probably pretty good...
return true;
@ -450,7 +491,7 @@ class InvenTreeAPI {
// Any "older" version of the server allows any API method for any logged in user!
// We will return immediately, but request the user roles in the background
var response = await get(_URL_GET_ROLES, expectedStatusCode: 200);
final response = await get(_URL_GET_ROLES, expectedStatusCode: 200);
if (!response.successful()) {
return;
@ -460,7 +501,31 @@ class InvenTreeAPI {
if (data.containsKey("roles")) {
// Save a local copy of the user roles
roles = response.data["roles"] as Map<String, dynamic>;
roles = (response.data["roles"] ?? {}) as Map<String, dynamic>;
}
}
// Request plugin information from the server
Future<void> getPluginInformation() async {
// The server does not support plugins, or they are not enabled
if (!pluginsEnabled()) {
_plugins.clear();
return;
}
print("Requesting plugin information");
// Request a list of plugins from the server
final List<InvenTreeModel> results = await InvenTreePlugin().list();
for (var result in results) {
if (result is InvenTreePlugin) {
if (result.active) {
// Only add plugins that are active
_plugins.add(result);
}
}
}
}

View File

@ -778,8 +778,6 @@ Map<String, dynamic> extractFieldDefinition(Map<String, dynamic> data, String lo
String el = path.last;
if (!_data.containsKey(el)) {
print("Could not find field definition for ${lookup}");
print("- Final field path ${el} missing from data");
return {};
} else {
@ -824,24 +822,28 @@ Future<void> launchApiForm(
IconData icon = FontAwesomeIcons.save,
}) async {
var options = await InvenTreeAPI().options(url);
// Invalid response from server
if (!options.isValid()) {
return;
}
// List of fields defined by the server
Map<String, dynamic> serverFields = extractFields(options);
Map<String, dynamic> serverFields = {};
if (serverFields.isEmpty) {
// User does not have permission to perform this action
showSnackIcon(
L10().response403,
icon: FontAwesomeIcons.userTimes,
);
if (url.isNotEmpty) {
var options = await InvenTreeAPI().options(url);
return;
// Invalid response from server
if (!options.isValid()) {
return;
}
serverFields = extractFields(options);
if (serverFields.isEmpty) {
// User does not have permission to perform this action
showSnackIcon(
L10().response403,
icon: FontAwesomeIcons.userTimes,
);
return;
}
}
// Construct a list of APIFormField objects
@ -868,8 +870,7 @@ Future<void> launchApiForm(
// Skip fields with empty definitions
if (field.definition.isEmpty) {
print("ERROR: Empty field definition for field '${fieldName}'");
continue;
print("Warning: Empty field definition for field '${fieldName}'");
}
// Add instance value to the field
@ -1170,6 +1171,23 @@ class _APIFormWidgetState extends State<APIFormWidget> {
}
}
// Run custom onSuccess function
var successFunc = onSuccess;
// An "empty" URL means we don't want to submit the form anywhere
// Perhaps we just want to process the data?
if (url.isEmpty) {
// Hide the form
Navigator.pop(context);
if (successFunc != null) {
// Return the raw "submitted" data, rather than the server response
successFunc(data);
}
return;
}
final response = await _submit(data);
if (!response.isValid()) {
@ -1187,9 +1205,6 @@ class _APIFormWidgetState extends State<APIFormWidget> {
// TODO: Display a snackBar
// Run custom onSuccess function
var successFunc = onSuccess;
if (successFunc != null) {
// Ensure the response is a valid JSON structure

View File

@ -500,6 +500,41 @@ class InvenTreeModel {
}
/*
* Class representing a single plugin instance
*/
class InvenTreePlugin extends InvenTreeModel {
InvenTreePlugin() : super();
InvenTreePlugin.fromJson(Map<String, dynamic> json) : super.fromJson(json);
@override
InvenTreeModel createFromJson(Map<String, dynamic> json) {
return InvenTreePlugin.fromJson(json);
}
@override
String get URL => "plugin/";
String get key => (jsondata["key"] ?? "") as String;
bool get active => (jsondata["active"] ?? false) as bool;
// Return the metadata struct for this plugin
Map<String, dynamic> get _meta => (jsondata["meta"] ?? {}) as Map<String, dynamic>;
String get humanName => (_meta["human_name"] ?? "") as String;
// Return the mixins struct for this plugin
Map<String, dynamic> get _mixins => (jsondata["mixins"] ?? {}) as Map<String, dynamic>;
bool supportsMixin(String mixin) {
return _mixins.containsKey(mixin);
}
}
class InvenTreeAttachment extends InvenTreeModel {
// Class representing an "attachment" file
InvenTreeAttachment() : super();

@ -1 +1 @@
Subproject commit 2396ebd447a616b5eebddd8d4ee407253d678d2f
Subproject commit 42662619b3d094e9bd41d3f715cac2beff7cf6f6

View File

@ -227,6 +227,8 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
List<Widget> children = [];
// TODO: Add in this option once the SupplierPart detail view is implemented
/*
children.add(
SimpleDialogOption(
onPressed: () {
@ -240,6 +242,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg
)
)
);
*/
if (order.isPlaced && InvenTreeAPI().supportPoReceive()) {
children.add(

View File

@ -84,6 +84,10 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
// StockItem object
final InvenTreeStockItem item;
// Is label printing enabled for this StockItem?
// This will be determined when the widget is loaded
List<Map<String, dynamic>> labels = [];
// Part object
InvenTreePart? part;
@ -103,8 +107,127 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
// Request part information
part = await InvenTreePart().get(item.partId) as InvenTreePart?;
// Request test results...
await item.getTestResults();
// Request test results (async)
item.getTestResults().then((value) {
setState(() {
// Update
});
});
// Request information on labels available for this stock item
if (InvenTreeAPI().pluginsEnabled()) {
_getLabels();
}
}
Future <void> _getLabels() async {
// Clear the existing labels list
labels.clear();
// If the server does not support label printing, don't bother!
if (!InvenTreeAPI().supportsMixin("labels")) {
return;
}
InvenTreeAPI().get(
"/label/stock/",
params: {
"enabled": "true",
"item": "${item.pk}",
},
).then((APIResponse response) {
if (response.isValid() && response.statusCode == 200) {
for (var label in response.data) {
if (label is Map<String, dynamic>) {
labels.add(label);
}
}
setState(() {
});
}
});
}
/// Opens a popup dialog allowing user to select a label for printing
Future <void> _printLabel(BuildContext context) async {
var plugins = InvenTreeAPI().getPlugins(mixin: "labels");
dynamic initial_label;
dynamic initial_plugin;
List<Map<String, dynamic>> label_options = [];
List<Map<String, dynamic>> plugin_options = [];
for (var label in labels) {
label_options.add({
"display_name": label["description"],
"value": label["pk"],
});
}
for (var plugin in plugins) {
plugin_options.add({
"display_name": plugin.humanName,
"value": plugin.key,
});
}
if (labels.length == 1) {
initial_label = labels.first["pk"];
}
if (plugins.length == 1) {
initial_plugin = plugins.first.key;
}
Map<String, dynamic> fields = {
"label": {
"label": "Label Template",
"type": "choice",
"value": initial_label,
"choices": label_options,
"required": true,
},
"plugin": {
"label": "Printer",
"type": "choice",
"value": initial_plugin,
"choices": plugin_options,
"required": true,
}
};
launchApiForm(
context,
L10().printLabel,
"",
fields,
icon: FontAwesomeIcons.print,
onSuccess: (Map<String, dynamic> data) async {
int labelId = (data["label"] ?? -1) as int;
String pluginKey = (data["plugin"] ?? "") as String;
if (labelId != -1 && pluginKey.isNotEmpty) {
String url = "/label/stock/${labelId}/print/?item=${item.pk}&plugin=${pluginKey}";
InvenTreeAPI().get(url).then((APIResponse response) {
if (response.isValid() && response.statusCode == 200) {
showSnackIcon(
L10().printLabelSuccess,
success: true
);
} else {
showSnackIcon(
L10().printLabelFailure,
success: false,
);
}
});
}
},
);
}
Future <void> _editStockItem(BuildContext context) async {
@ -859,6 +982,19 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
);
}
// Print label (if label printing plugins exist)
if (labels.isNotEmpty) {
tiles.add(
ListTile(
title: Text(L10().printLabel),
leading: FaIcon(FontAwesomeIcons.print, color: COLOR_CLICK),
onTap: () {
_printLabel(context);
},
),
);
}
return tiles;
}

View File

@ -7,21 +7,21 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.2"
version: "3.2.2"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.3.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.6.1"
version: "2.8.2"
audioplayers:
dependency: "direct main"
description:
@ -35,7 +35,7 @@ packages:
name: back_button_interceptor
url: "https://pub.dartlang.org"
source: hosted
version: "5.0.1"
version: "5.0.2"
boolean_selector:
dependency: transitive
description:
@ -49,7 +49,7 @@ packages:
name: cached_network_image
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "3.2.0"
cached_network_image_platform_interface:
dependency: transitive
description:
@ -70,28 +70,35 @@ packages:
name: camera
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.1+3"
version: "0.9.4+16"
camera_platform_interface:
dependency: transitive
description:
name: camera_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.1.5"
camera_web:
dependency: transitive
description:
name: camera_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.1+3"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "1.3.1"
clock:
dependency: transitive
description:
@ -112,7 +119,7 @@ packages:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.1+1"
version: "0.3.2"
crypto:
dependency: transitive
description:
@ -126,7 +133,7 @@ packages:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.4"
datetime_picker_formfield:
dependency: "direct main"
description:
@ -140,28 +147,28 @@ packages:
name: device_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.0"
device_info_plus_linux:
dependency: transitive
description:
name: device_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
device_info_plus_macos:
dependency: transitive
description:
name: device_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.2"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.3.0+1"
device_info_plus_web:
dependency: transitive
description:
@ -175,7 +182,7 @@ packages:
name: device_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
dropdown_search:
dependency: "direct main"
description:
@ -210,7 +217,7 @@ packages:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
version: "4.5.1"
flutter:
dependency: "direct main"
description: flutter
@ -222,21 +229,21 @@ packages:
name: flutter_blurhash
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.0"
version: "0.6.4"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.2"
version: "3.3.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.0"
version: "0.9.2"
flutter_localizations:
dependency: "direct main"
description: flutter
@ -248,14 +255,14 @@ packages:
name: flutter_markdown
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.2"
version: "0.6.9"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
version: "2.0.5"
flutter_test:
dependency: "direct dev"
description: flutter
@ -272,14 +279,14 @@ packages:
name: font_awesome_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "9.1.0"
version: "9.2.0"
http:
dependency: "direct main"
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.3"
version: "0.13.4"
http_parser:
dependency: transitive
description:
@ -293,28 +300,28 @@ packages:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
version: "3.1.3"
image_picker:
dependency: "direct main"
description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.3+2"
version: "0.8.4+11"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.6"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "2.4.4"
infinite_scroll_pagination:
dependency: "direct main"
description:
@ -342,42 +349,49 @@ packages:
name: lint
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
version: "1.8.2"
markdown:
dependency: transitive
description:
name: markdown
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
version: "4.0.1"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.10"
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
version: "1.7.0"
octo_image:
dependency: transitive
description:
name: octo_image
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0+1"
version: "1.0.1"
one_context:
dependency: "direct main"
description:
name: one_context
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.1.1"
open_file:
dependency: "direct main"
description:
@ -391,7 +405,7 @@ packages:
name: package_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "1.4.0"
package_info_plus_linux:
dependency: transitive
description:
@ -405,7 +419,7 @@ packages:
name: package_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.3.0"
package_info_plus_platform_interface:
dependency: transitive
description:
@ -419,14 +433,14 @@ packages:
name: package_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.4"
package_info_plus_windows:
dependency: transitive
description:
name: package_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.4"
path:
dependency: "direct main"
description:
@ -447,28 +461,28 @@ packages:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.5"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.5"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.3"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.5"
pedantic:
dependency: transitive
description:
@ -482,28 +496,28 @@ packages:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
version: "4.4.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.2"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.1"
version: "4.2.4"
qr_code_scanner:
dependency: "direct main"
description:
@ -517,21 +531,21 @@ packages:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "3.0.1+1"
rxdart:
dependency: transitive
description:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.27.1"
version: "0.27.3"
sembast:
dependency: "direct main"
description:
name: sembast
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0+2"
version: "3.2.0"
sentry:
dependency: transitive
description:
@ -552,21 +566,35 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
version: "2.0.13"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.0"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.3"
shared_preferences_platform_interface:
dependency: transitive
description:
@ -580,14 +608,14 @@ packages:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.3"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.1.0"
sky_engine:
dependency: transitive
description: flutter
@ -613,14 +641,14 @@ packages:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0+3"
version: "2.0.2"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0+2"
version: "2.2.1"
stack_trace:
dependency: transitive
description:
@ -669,7 +697,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "0.4.8"
typed_data:
dependency: transitive
description:
@ -690,70 +718,70 @@ packages:
name: url_launcher_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.3"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.3"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.5"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "2.0.9"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "2.0.2"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.4"
version: "3.0.6"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.1.1"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
version: "2.4.2"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "0.2.0+1"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.2"
version: "5.3.1"
yaml:
dependency: transitive
description:
@ -762,5 +790,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.13.0 <3.0.0"
flutter: ">=2.0.0"
dart: ">=2.16.0 <3.0.0"
flutter: ">=2.10.0"