Implement multi-note support (#883)

* Implement multi-note support

Ref: https://github.com/inventree/InvenTree/pull/11971

* Bump iOS target
This commit is contained in:
Oliver
2026-09-12 08:41:11 +10:00
committed by GitHub
parent 923479c38c
commit 5b40a0d3b6
17 changed files with 529 additions and 118 deletions
+6
View File
@@ -1,3 +1,9 @@
## xx.yy.z - Month Year
---
- Supports new multi-note API for model instances
- Implement rendering for HTML note content
## 0.25.2 - September 2026
---
+1 -1
View File
@@ -39,7 +39,7 @@ post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
end
+5
View File
@@ -344,6 +344,11 @@ class InvenTreeAPI {
// Ref: https://github.com/inventree/InvenTree/pull/12011
bool get supportsStockItemCreationDate => apiVersion >= 496;
// Does the server support the "multi notes" API?
// (Multiple HTML notes may be attached to a single model instance)
// Ref: https://github.com/inventree/InvenTree/pull/11971
bool get supportsMultiNotes => apiVersion >= 537;
// Cached list of plugins (refreshed when we connect to the server)
List<InvenTreePlugin> _plugins = [];
+39
View File
@@ -0,0 +1,39 @@
import "package:inventree/inventree/model.dart";
/*
* Class representing a single "note" entry.
*
* Notes can be attached to any model instance which supports the
* InvenTree "multi notes" API - multiple notes may be attached to
* a single model instance.
*
* Note content is provided by the server as editor-agnostic HTML,
* and cannot be edited from within this app.
*
* Ref: https://github.com/inventree/InvenTree/pull/11971
*/
class InvenTreeNoteEntry extends InvenTreeModel {
InvenTreeNoteEntry() : super();
InvenTreeNoteEntry.fromJson(Map<String, dynamic> json) : super.fromJson(json);
@override
InvenTreeNoteEntry createFromJson(Map<String, dynamic> json) =>
InvenTreeNoteEntry.fromJson(json);
@override
String get URL => "note/";
// The model type of the instance this note is associated with
String get modelType => getString("model_type");
// The ID of the instance this note is associated with
int get modelId => getInt("model_id");
String get title => getString("title");
// Rendered (HTML) content of this note
String get content => getString("content");
DateTime? get updated => getDate("updated");
}
+3
View File
@@ -953,6 +953,9 @@
"description": "Notes"
},
"noNotesFound": "No notes found",
"@noNotesFound": {},
"notifications": "Notifications",
"@notifications": {},
+2 -12
View File
@@ -13,7 +13,7 @@ import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/build/build_line_list.dart";
import "package:inventree/widget/build/build_item_list.dart";
@@ -553,17 +553,7 @@ class _BuildOrderDetailState extends RefreshableState<BuildOrderDetailWidget> {
// Notes tile
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.notes, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotesWidget(widget.order)),
);
},
),
ShowNotesItem(context, widget.order, InvenTreeBuildOrder.MODEL_TYPE),
);
// Attachments tile
+4 -10
View File
@@ -13,6 +13,7 @@ import "package:inventree/inventree/purchase_order.dart";
import "package:inventree/inventree/sales_order.dart";
import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/order/purchase_order_list.dart";
import "package:inventree/widget/order/sales_order_list.dart";
import "package:inventree/widget/parameter_widget.dart";
@@ -400,16 +401,9 @@ class _CompanyDetailState extends RefreshableState<CompanyDetailWidget> {
);
}
if (widget.company.notes.isNotEmpty) {
tiles.add(
ListTile(
title: Text(L10().notes),
subtitle: Text(widget.company.notes),
leading: Icon(TablerIcons.note),
onTap: null,
),
);
}
tiles.add(
ShowNotesItem(context, widget.company, InvenTreeCompany.MODEL_TYPE),
);
ListTile? parameterTile = ShowParametersItem(
context,
+176
View File
@@ -0,0 +1,176 @@
import "package:cached_network_image/cached_network_image.dart";
import "package:flutter/material.dart";
import "package:flutter_tabler_icons/flutter_tabler_icons.dart";
import "package:flutter_widget_from_html/flutter_widget_from_html.dart";
import "package:inventree/api.dart";
import "package:inventree/app_colors.dart";
import "package:inventree/inventree/model.dart";
import "package:inventree/inventree/notes.dart";
import "package:inventree/l10.dart";
import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/refreshable_state.dart";
/*
* A widget for displaying the list of "notes" attached to a given model instance,
* for servers which support the "multi notes" API.
*
* Note content is rendered as HTML, and cannot be edited from within the app.
*
* Ref: https://github.com/inventree/InvenTree/pull/11971
*/
class NotesListWidget extends StatefulWidget {
const NotesListWidget(this.modelType, this.modelId, {Key? key})
: super(key: key);
final String modelType;
final int modelId;
@override
_NotesListWidgetState createState() => _NotesListWidgetState();
}
class _NotesListWidgetState extends RefreshableState<NotesListWidget> {
_NotesListWidgetState();
List<InvenTreeNoteEntry> notes = [];
@override
String getAppBarTitle() => L10().notes;
@override
Future<void> request(BuildContext context) async {
Map<String, String> filters = {
"model_type": widget.modelType,
"model_id": widget.modelId.toString(),
};
List<InvenTreeNoteEntry> results = [];
await InvenTreeNoteEntry().list(filters: filters).then((var entries) {
for (var entry in entries) {
if (entry is InvenTreeNoteEntry) {
results.add(entry);
}
}
});
if (mounted) {
setState(() {
notes = results;
});
}
}
@override
List<Widget> getTiles(BuildContext context) {
List<Widget> tiles = [];
for (var note in notes) {
tiles.add(
ListTile(
title: Text(note.title.isNotEmpty ? note.title : L10().notes),
subtitle: note.description.isNotEmpty ? Text(note.description) : null,
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NoteViewWidget(note)),
);
},
),
);
}
if (tiles.isEmpty && !loading) {
tiles.add(
ListTile(
leading: Icon(TablerIcons.note_off, color: COLOR_WARNING),
title: Text(L10().noNotesFound),
),
);
}
return tiles;
}
}
/*
* Custom WidgetFactory which authenticates image requests against the
* InvenTree server, so that (e.g.) note images hosted behind the server's
* media API can be displayed.
*/
class _NoteWidgetFactory extends WidgetFactory {
@override
ImageProvider<Object>? imageProviderFromNetwork(String url) {
if (url.isEmpty) {
return null;
}
return CachedNetworkImageProvider(
url,
headers: InvenTreeAPI().defaultHeaders(),
cacheManager: InvenTreeAPI().imageCacheManager,
);
}
}
/*
* A read-only widget for viewing the (HTML) content of a single note.
*
* Note content is generated server-side by a rich text editor,
* and cannot be edited from within this app.
*/
class NoteViewWidget extends StatelessWidget {
const NoteViewWidget(this.note, {Key? key}) : super(key: key);
final InvenTreeNoteEntry note;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(note.title.isNotEmpty ? note.title : L10().notes),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(12),
child: HtmlWidget(
note.content,
baseUrl: Uri.tryParse(InvenTreeAPI().baseUrl),
factoryBuilder: () => _NoteWidgetFactory(),
),
),
);
}
}
/*
* Return a ListTile which navigates to the "notes" for the given model instance.
*
* If the server supports the "multi notes" API, the user is first presented
* with a list of available notes to select from.
*
* Otherwise, we fall back to the legacy single-notes (markdown) implementation.
*/
ListTile ShowNotesItem(
BuildContext context,
InvenTreeModel model,
String modelType,
) {
return ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InvenTreeAPI().supportsMultiNotes
? NotesListWidget(modelType, model.pk)
: LegacyNotesWidget(model),
),
);
},
);
}
+9 -8
View File
@@ -6,26 +6,27 @@ import "package:flutter_markdown/flutter_markdown.dart";
import "package:inventree/l10.dart";
/*
* A widget for displaying the notes associated with a given model.
* A widget for displaying the single (markdown) notes field associated with
* a given model, for servers which do not support the "multi notes" API.
* We need to pass in the following parameters:
*
*
* - Model instance
* - Title for the app bar
*/
class NotesWidget extends StatefulWidget {
const NotesWidget(this.model, {Key? key}) : super(key: key);
class LegacyNotesWidget extends StatefulWidget {
const LegacyNotesWidget(this.model, {Key? key}) : super(key: key);
final InvenTreeModel model;
@override
_NotesState createState() => _NotesState();
_LegacyNotesState createState() => _LegacyNotesState();
}
/*
* Class representing the state of the NotesWidget
* Class representing the state of the LegacyNotesWidget
*/
class _NotesState extends RefreshableState<NotesWidget> {
_NotesState();
class _LegacyNotesState extends RefreshableState<LegacyNotesWidget> {
_LegacyNotesState();
@override
Future<void> request(BuildContext context) async {
+2 -12
View File
@@ -22,7 +22,7 @@ import "package:inventree/widget/order/po_extra_line_list.dart";
import "package:inventree/widget/order/po_line_list.dart";
import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/progress.dart";
import "package:inventree/widget/refreshable_state.dart";
@@ -567,17 +567,7 @@ class _PurchaseOrderDetailState
// Notes tile
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotesWidget(widget.order)),
);
},
),
ShowNotesItem(context, widget.order, InvenTreePurchaseOrder.MODEL_TYPE),
);
ListTile? parameterTile = ShowParametersItem(
+2 -12
View File
@@ -20,7 +20,7 @@ import "package:inventree/l10.dart";
import "package:inventree/app_colors.dart";
import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/snacks.dart";
import "package:inventree/widget/progress.dart";
@@ -492,17 +492,7 @@ class _SalesOrderDetailState extends RefreshableState<SalesOrderDetailWidget> {
// Notes tile
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotesWidget(widget.order)),
);
},
),
ShowNotesItem(context, widget.order, InvenTreeSalesOrder.MODEL_TYPE),
);
ListTile? parameterTile = ShowParametersItem(
+5 -13
View File
@@ -14,7 +14,7 @@ import "package:inventree/l10.dart";
import "package:inventree/preferences.dart";
import "package:inventree/widget/attachment_widget.dart";
import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/order/so_allocation_list.dart";
import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/snacks.dart";
@@ -336,18 +336,10 @@ class _SOShipmentDetailWidgetState
// Notes tile
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotesWidget(widget.shipment),
),
);
},
ShowNotesItem(
context,
widget.shipment,
InvenTreeSalesOrderShipment.MODEL_TYPE,
),
);
+2 -12
View File
@@ -12,7 +12,7 @@ import "package:inventree/inventree/transfer_order.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/order/transfer_order_line_list.dart";
import "package:inventree/widget/progress.dart";
import "package:inventree/widget/refreshable_state.dart";
@@ -406,17 +406,7 @@ class _TransferOrderDetailState
}
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotesWidget(widget.order)),
);
},
),
ShowNotesItem(context, widget.order, InvenTreeTransferOrder.MODEL_TYPE),
);
return tiles;
+2 -14
View File
@@ -21,7 +21,7 @@ import "package:inventree/widget/link_icon.dart";
import "package:inventree/widget/parameter_widget.dart";
import "package:inventree/widget/part/bom_list.dart";
import "package:inventree/widget/part/part_list.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
import "package:inventree/widget/part/part_pricing.dart";
import "package:inventree/widget/progress.dart";
import "package:inventree/widget/part/category_display.dart";
@@ -726,19 +726,7 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> {
}
// Notes field
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotesWidget(part)),
);
},
),
);
tiles.add(ShowNotesItem(context, part, InvenTreePart.MODEL_TYPE));
ListTile? parameterTile = ShowParametersItem(
context,
+2 -12
View File
@@ -27,7 +27,7 @@ import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/snacks.dart";
import "package:inventree/widget/stock/stock_item_history.dart";
import "package:inventree/widget/stock/stock_item_test_results.dart";
import "package:inventree/widget/notes_widget.dart";
import "package:inventree/widget/notes_list_widget.dart";
class StockDetailWidget extends StatefulWidget {
const StockDetailWidget(this.item, {Key? key}) : super(key: key);
@@ -840,17 +840,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
// Notes field
tiles.add(
ListTile(
title: Text(L10().notes),
leading: Icon(TablerIcons.note, color: COLOR_ACTION),
trailing: LinkIcon(),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NotesWidget(widget.item)),
);
},
),
ShowNotesItem(context, widget.item, InvenTreeStockItem.MODEL_TYPE),
);
ListTile? attachmentTile = ShowAttachmentsItem(
+268 -12
View File
@@ -49,6 +49,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.13.0"
audio_session:
dependency: transitive
description:
name: audio_session
sha256: f9e7711a0e24ca8b40f5d7ac374c3c6e55016f3157912badd18199cdbbca5c4d
url: "https://pub.dev"
source: hosted
version: "0.2.4"
audioplayers:
dependency: "direct main"
description:
@@ -189,10 +197,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.4.0"
checked_yaml:
dependency: transitive
description:
@@ -201,6 +209,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.4"
chewie:
dependency: transitive
description:
name: chewie
sha256: "53dadd2c5b6748742d7744072b38a417ad22691ca55715850300ee793dc7cb27"
url: "https://pub.dev"
source: hosted
version: "1.13.1"
cli_config:
dependency: transitive
description:
@@ -265,6 +281,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.6"
csslib:
dependency: transitive
description:
name: csslib
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
cupertino_icons:
dependency: "direct main"
description:
@@ -523,6 +547,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.0"
flutter_svg:
dependency: transitive
description:
name: flutter_svg
sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
flutter_tabler_icons:
dependency: "direct main"
description:
@@ -541,6 +573,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_widget_from_html:
dependency: "direct main"
description:
name: flutter_widget_from_html
sha256: "16fedbf9cc41656d50a2d27b7ef196bfe85c3fcecb2c84e69e288a1fb2154a1b"
url: "https://pub.dev"
source: hosted
version: "0.17.4"
flutter_widget_from_html_core:
dependency: transitive
description:
name: flutter_widget_from_html_core
sha256: "530f2e3cc57be1a00f8bfae1b0000064e8a6df0cf1fb4d48a80f85afde9b39b7"
url: "https://pub.dev"
source: hosted
version: "0.17.4"
frontend_server_client:
dependency: transitive
description:
@@ -549,6 +597,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
fwfh_cached_network_image:
dependency: transitive
description:
name: fwfh_cached_network_image
sha256: abbe8f65f3468bfdede4e450b2afffbdc0363f12bf0bdfef3815d47625446bb4
url: "https://pub.dev"
source: hosted
version: "0.16.3"
fwfh_chewie:
dependency: transitive
description:
name: fwfh_chewie
sha256: ae74fc26798b0e74f3983f7b851e74c63b9eeb2d3015ecd4b829096b2c3f8818
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_just_audio:
dependency: transitive
description:
name: fwfh_just_audio
sha256: dfd622a0dfe049ac647423a2a8afa7f057d9b2b93d92710b624e3d370b1ac69a
url: "https://pub.dev"
source: hosted
version: "0.17.0"
fwfh_svg:
dependency: transitive
description:
name: fwfh_svg
sha256: "2e6bb241179eeeb1a7941e05c8c923b05d332d36a9085233e7bf110ea7deb915"
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_url_launcher:
dependency: transitive
description:
name: fwfh_url_launcher
sha256: c38aa8fb373fda3a89b951fa260b539f623f6edb45eee7874cb8b492471af881
url: "https://pub.dev"
source: hosted
version: "0.16.1"
fwfh_webview:
dependency: transitive
description:
name: fwfh_webview
sha256: a9cdfbe58a7152bcc91c420dc96cd9972c01b5d1318a6d4c6d9a1d97a1bd6e94
url: "https://pub.dev"
source: hosted
version: "0.15.8"
gesture_x_detector:
dependency: transitive
description:
@@ -565,6 +661,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.3"
html:
dependency: transitive
description:
name: html
sha256: "43b67b8f43321ab066817dfac5619596c98bb1b61624e77203bb4351785f9699"
url: "https://pub.dev"
source: hosted
version: "0.15.7"
http:
dependency: "direct main"
description:
@@ -693,6 +797,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.14.2"
js:
dependency: transitive
description:
name: js
sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
json_annotation:
dependency: transitive
description:
@@ -701,6 +813,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.9.0"
just_audio:
dependency: transitive
description:
name: just_audio
sha256: e60aa97b233ddea025e13dfac59195207f528fa5e9e4a4a49a8c0766701e5fe6
url: "https://pub.dev"
source: hosted
version: "0.10.6"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
sha256: "2532c8d6702528824445921c5ff10548b518b13f808c2e34c2fd54793b999a6a"
url: "https://pub.dev"
source: hosted
version: "4.6.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
sha256: "6ba8a2a7e87d57d32f0f7b42856ade3d6a9fbe0f1a11fabae0a4f00bb73f0663"
url: "https://pub.dev"
source: hosted
version: "0.4.16"
leak_tracker:
dependency: transitive
description:
@@ -753,18 +889,18 @@ packages:
dependency: transitive
description:
name: matcher
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.19"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.13.0"
version: "0.11.1"
meta:
dependency: transitive
description:
@@ -789,6 +925,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.2.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
node_preamble:
dependency: transitive
description:
@@ -853,6 +997,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
path_provider:
dependency: "direct main"
description:
@@ -949,6 +1101,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.2"
provider:
dependency: transitive
description:
name: provider
sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272"
url: "https://pub.dev"
source: hosted
version: "6.1.5+1"
pub_semver:
dependency: transitive
description:
@@ -1214,26 +1374,26 @@ packages:
dependency: "direct dev"
description:
name: test
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7"
url: "https://pub.dev"
source: hosted
version: "1.30.0"
version: "1.26.3"
test_api:
dependency: transitive
description:
name: test_api
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.7"
test_core:
dependency: transitive
description:
name: test_core
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0"
url: "https://pub.dev"
source: hosted
version: "0.6.16"
version: "0.6.12"
typed_data:
dependency: transitive
description:
@@ -1314,6 +1474,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.5.1"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "9d0e3b9cb16542ad660daee871e726a10d13a93b7b5391677c3160e8f5e83935"
url: "https://pub.dev"
source: hosted
version: "1.2.3"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146"
url: "https://pub.dev"
source: hosted
version: "1.1.13"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "4dca4feb77dc3ec7f6e27e49c53241eb8217f55e4f9b12599a27f8903bca5682"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
vector_math:
dependency: transitive
description:
@@ -1322,6 +1506,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
video_player:
dependency: transitive
description:
name: video_player
sha256: "48a7bdaa38a3d50ec10c78627abdbfad863fdf6f0d6e08c7c3c040cfd80ae36f"
url: "https://pub.dev"
source: hosted
version: "2.11.1"
video_player_android:
dependency: transitive
description:
name: video_player_android
sha256: "877a6c7ba772456077d7bfd71314629b3fe2b73733ce503fc77c3314d43a0ca0"
url: "https://pub.dev"
source: hosted
version: "2.9.5"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
sha256: "2fc56e537324a19eb649fca991aa308ac961b5406292876fa657b062de461fd8"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
sha256: "92c0fbabe20c788e71fd10d26cea998d0d253282e65d145aed0818731cf593ce"
url: "https://pub.dev"
source: hosted
version: "6.9.0"
video_player_web:
dependency: transitive
description:
name: video_player_web
sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
vm_service:
dependency: transitive
description:
@@ -1386,6 +1610,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
webview_flutter:
dependency: transitive
description:
name: webview_flutter
sha256: d53e1ccf5516f25017e3c9d44c39034db352d20fa34fe200674270242c2c5111
url: "https://pub.dev"
source: hosted
version: "4.14.1"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: ad5182eff9a550925330cb9f0cb038eddfdd5712aba8b77aa0f0400e50f6e688
url: "https://pub.dev"
source: hosted
version: "4.12.0"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "1221c1b12f5278791042f2ec2841743784cf25c5a644e23d6680e5d718824f04"
url: "https://pub.dev"
source: hosted
version: "2.15.1"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: "82648217f537573e1ca9ae9952d3eacedca6ab5aee69dc84445fc763766dcea2"
url: "https://pub.dev"
source: hosted
version: "3.25.1"
win32:
dependency: transitive
description:
+1
View File
@@ -30,6 +30,7 @@ dependencies:
flutter_secure_storage: ^10.3.1
flutter_speed_dial: ^6.2.0 # Speed dial / FAB implementation
flutter_tabler_icons: ^1.43.0 # Tabler icons
flutter_widget_from_html: ^0.17.4 # Rendering HTML (multi-notes)
http: ^1.4.0
image: ^4.5.4 # Re-encode/compress images before upload
image_picker: ^1.2.2 # Select or take photos