Commit 7a2262d
Changed files (8)
lib
components
dialoges
measurement_list
l10n
screens
test
lib/components/dialoges/add_measurement_dialoge.dart
@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:blood_pressure_app/components/date_time_picker.dart';
import 'package:blood_pressure_app/components/dialoges/fullscreen_dialoge.dart';
import 'package:blood_pressure_app/components/settings/settings_widgets.dart';
+import 'package:blood_pressure_app/model/blood_pressure/medicine/medicine_intake.dart';
import 'package:blood_pressure_app/model/blood_pressure/needle_pin.dart';
import 'package:blood_pressure_app/model/blood_pressure/record.dart';
import 'package:blood_pressure_app/model/storage/storage.dart';
@@ -12,11 +13,11 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
/// Input mask for entering measurements.
-class AddMeasurementDialoge extends StatefulWidget {
+class AddEntryDialoge extends StatefulWidget {
/// Create a input mask for entering measurements.
///
- /// This is usually created through the [showAddMeasurementDialoge] function.
- const AddMeasurementDialoge({super.key,
+ /// This is usually created through the [showAddEntryDialoge] function.
+ const AddEntryDialoge({super.key,
required this.settings,
this.initialRecord,
});
@@ -30,10 +31,10 @@ class AddMeasurementDialoge extends StatefulWidget {
final BloodPressureRecord? initialRecord;
@override
- State<AddMeasurementDialoge> createState() => _AddMeasurementDialogeState();
+ State<AddEntryDialoge> createState() => _AddEntryDialogeState();
}
-class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
+class _AddEntryDialogeState extends State<AddEntryDialoge> {
final formKey = GlobalKey<FormState>();
final sysFocusNode = FocusNode();
final diaFocusNode = FocusNode();
@@ -59,6 +60,15 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
/// Last [FormState.save]d note.
String? notes;
+
+ /// Index of the medicine intake that can me entered here.
+ int? medicineId;
+
+ /// Whether to show the medication dosis input
+ bool _showMedicineDosisInput = false;
+
+ /// Entered dosis of medication.
+ double? medicineDosis;
@override
void initState() {
@@ -99,13 +109,7 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
ListTile(
title: Text(DateFormat(widget.settings.dateFormatString).format(time)),
trailing: const Icon(Icons.edit),
- shape: RoundedRectangleBorder(
- side: BorderSide(
- width: 2,
- color: Theme.of(context).primaryColor
- ),
- borderRadius: BorderRadius.circular(20)
- ),
+ shape: buildListTileBorder(),
onTap: () async {
final messenger = ScaffoldMessenger.of(context);
var selectedTime = await showDateTimePicker(
@@ -156,6 +160,11 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
}
},
validator: (String? value) {
+ // Indicates that only a medicine intake is wanted.
+ if (_showMedicineDosisInput && medicineDosis != null &&
+ medicineId != null && systolic == null && diastolic == null &&
+ pulse == null && notes == null && needlePin == null) return null;
+
if (!widget.settings.allowMissingValues && (value == null || value.isEmpty || int.tryParse(value) == null)) {
return localizations.errNaN;
} else if (widget.settings.validateInputs && (int.tryParse(value ?? '') ?? -1) <= 30) {
@@ -188,6 +197,14 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
);
}
+ RoundedRectangleBorder buildListTileBorder([Color? color]) => RoundedRectangleBorder(
+ side: BorderSide(
+ width: 2,
+ color: color ?? Theme.of(context).primaryColor
+ ),
+ borderRadius: BorderRadius.circular(20)
+ );
+
@override
Widget build(BuildContext context) {
final localizations = AppLocalizations.of(context)!;
@@ -195,8 +212,21 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
onActionButtonPressed: () {
if (formKey.currentState?.validate() ?? false) {
formKey.currentState?.save();
- final record = BloodPressureRecord(time, systolic, diastolic, pulse, notes ?? '', needlePin: needlePin);
- Navigator.of(context).pop(record);
+ MedicineIntake? intake;
+ if (_showMedicineDosisInput && medicineDosis != null && medicineId != null) {
+ intake = MedicineIntake(
+ timestamp: time,
+ medicine: widget.settings.medications.where((e) => e.id == medicineId).first,
+ dosis: medicineDosis!,
+ );
+ }
+ BloodPressureRecord? record;
+ if (systolic != null && diastolic != null && pulse != null
+ && notes != null && needlePin != null) {
+ record = BloodPressureRecord(time, systolic, diastolic, pulse, notes ?? '', needlePin: needlePin);
+ }
+
+ Navigator.of(context).pop((record, intake));
}
},
actionButtonText: localizations.btnSave,
@@ -248,6 +278,7 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
decoration: getInputDecoration(localizations.addNote),
minLines: 1,
//maxLines: 4, There is a bug in the flutter framework: https://github.com/flutter/flutter/issues/138219
+ // TODO Material.of(context).markNeedsPaint()
onSaved: (value) => setState(() => notes = value),
),
),
@@ -259,14 +290,78 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
});
},
initialColor: needlePin?.color ?? Colors.transparent,
- shape: RoundedRectangleBorder(
- side: BorderSide(
- width: 2,
- color: needlePin?.color ?? Theme.of(context).primaryColor
- ),
- borderRadius: BorderRadius.circular(20)
- )
+ shape: buildListTileBorder(needlePin?.color)
),
+ if (widget.settings.medications.isNotEmpty)
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 16),
+ child: Row(
+ children: [
+ Expanded(
+ child: ListTile(
+ shape: buildListTileBorder(),
+ title: DropdownButton( // TODO medicine intake
+ isExpanded: true,
+ value: widget.settings.medications
+ .where((e) => e.id == medicineId).firstOrNull,
+ underline: const SizedBox.shrink(),
+ items: [
+ for (final e in widget.settings.medications)
+ DropdownMenuItem(
+ value: e,
+ child: Text(e.designation),
+ ),
+ DropdownMenuItem(
+ value: null,
+ child: Text(localizations.noMedication),
+ )
+ ],
+ onChanged: (v) {
+ setState(() {
+ if (v != null) {
+ _showMedicineDosisInput = true;
+ medicineId = v.id;
+ medicineDosis = v.defaultDosis;
+ } else {
+ _showMedicineDosisInput = false;
+ medicineId = null;
+ }
+ Material.of(context).markNeedsPaint();
+ });
+ // TODO
+ }
+ ),
+ ),
+ ),
+ if (_showMedicineDosisInput)
+ const SizedBox(width: 16,),
+ if (_showMedicineDosisInput)
+ Expanded(
+ child: TextFormField(
+ initialValue: medicineDosis?.toString(),
+ decoration: getInputDecoration(localizations.dosis),
+ keyboardType: TextInputType.number,
+ onSaved: (value) => setState(() {
+ final dosis = int.tryParse(value ?? '')?.toDouble()
+ ?? double.tryParse(value ?? '');
+ if(dosis != null && dosis > 0) medicineDosis = dosis;
+ }),
+ inputFormatters: [FilteringTextInputFormatter.allow(
+ RegExp(r'([0-9]+(\.([0-9]*))?)'))],
+ validator: (String? value) {
+ if (!_showMedicineDosisInput) return null;
+ if (((int.tryParse(value ?? '')?.toDouble()
+ ?? double.tryParse(value ?? '')) ?? 0) <= 0) {
+ return localizations.errNaN;
+ }
+ return null;
+ },
+ ),
+ ),
+
+ ],
+ ),
+ ),
],
),
),
@@ -275,7 +370,16 @@ class _AddMeasurementDialogeState extends State<AddMeasurementDialoge> {
}
/// Shows a dialoge to input a blood pressure measurement.
-Future<BloodPressureRecord?> showAddMeasurementDialoge(BuildContext context, Settings settings, [BloodPressureRecord? initialRecord]) =>
- showDialog<BloodPressureRecord?>(context: context, builder: (context) => Dialog.fullscreen(
- child: AddMeasurementDialoge(settings: settings, initialRecord: initialRecord,),
- ));
\ No newline at end of file
+Future<(BloodPressureRecord?, MedicineIntake?)?> showAddEntryDialoge(
+ BuildContext context,
+ Settings settings,
+ [BloodPressureRecord? initialRecord]) =>
+ showDialog<(BloodPressureRecord?, MedicineIntake?)>(
+ context: context, builder: (context) =>
+ Dialog.fullscreen(
+ child: AddEntryDialoge(
+ settings: settings,
+ initialRecord: initialRecord
+ ),
+ )
+ );
\ No newline at end of file
lib/components/measurement_list/measurement_list_entry.dart
@@ -32,15 +32,18 @@ class MeasurementListRow extends StatelessWidget {
children: [
IconButton(
onPressed: () async {
- final future = showAddMeasurementDialoge(context, settings, record);
final model = Provider.of<BloodPressureModel>(context, listen: false);
- final measurement = await future;
- if (measurement == null) return;
- if (context.mounted) {
- model.addAndExport(context, measurement);
- } else {
- model.add(measurement);
- assert(false, 'context not mounted');
+ final entry = await showAddEntryDialoge(context,
+ Provider.of<Settings>(context, listen: false));
+ if (entry?.$1 != null) {
+ if (context.mounted) {
+ model.addAndExport(context, entry!.$1!);
+ } else {
+ model.add(entry!.$1!);
+ }
+ }
+ if (entry?.$2 != null) {
+ // TODO: save medicine intake
}
},
icon: const Icon(Icons.edit),
lib/l10n/app_en.arb
@@ -496,5 +496,9 @@
"name": "Name",
"@name": {},
"defaultDosis": "default dosis",
- "@defaultDosis": {}
+ "@defaultDosis": {},
+ "noMedication": "No medication",
+ "@noMedication": {},
+ "dosis": "Dosis",
+ "@dosis": {}
}
lib/screens/elements/legacy_measurement_list.dart
@@ -83,14 +83,18 @@ class LegacyMeasurementsList extends StatelessWidget {
confirmDismiss: (direction) async {
final model = Provider.of<BloodPressureModel>(context, listen: false);
if (direction == DismissDirection.startToEnd) { // edit
- final future = showAddMeasurementDialoge(context, settings, data[index]);
final model = Provider.of<BloodPressureModel>(context, listen: false);
- final measurement = await future;
- if (measurement == null) return false;
- if (context.mounted) {
- model.addAndExport(context, measurement);
- } else {
- model.add(measurement);
+ final entry = await showAddEntryDialoge(context,
+ Provider.of<Settings>(context, listen: false));
+ if (entry?.$1 != null) {
+ if (context.mounted) {
+ model.addAndExport(context, entry!.$1!);
+ } else {
+ model.add(entry!.$1!);
+ }
+ }
+ if (entry?.$2 != null) {
+ // TODO: save medicine intake
}
return false;
} else { // delete
lib/screens/home_screen.dart
@@ -28,14 +28,18 @@ class AppHome extends StatelessWidget {
if (_appStart) {
if (Provider.of<Settings>(context, listen: false).startWithAddMeasurementPage) {
SchedulerBinding.instance.addPostFrameCallback((_) async {
- final future = showAddMeasurementDialoge(context, Provider.of<Settings>(context, listen: false));
final model = Provider.of<BloodPressureModel>(context, listen: false);
- final measurement = await future;
+ final measurement = await showAddEntryDialoge(context, Provider.of<Settings>(context, listen: false));
if (measurement == null) return;
- if (context.mounted) {
- model.addAndExport(context, measurement);
- } else {
- model.add(measurement);
+ if (measurement.$1 != null) {
+ if (context.mounted) {
+ model.addAndExport(context, measurement.$1!);
+ } else {
+ model.add(measurement.$1!);
+ }
+ }
+ if (measurement.$2 != null) {
+ // TODO: save medicine intake
}
});
}
@@ -94,14 +98,18 @@ class AppHome extends StatelessWidget {
tooltip: localizations.addMeasurement,
autofocus: true,
onPressed: () async {
- final future = showAddMeasurementDialoge(context, settings);
final model = Provider.of<BloodPressureModel>(context, listen: false);
- final measurement = await future;
+ final measurement = await showAddEntryDialoge(context, Provider.of<Settings>(context, listen: false));
if (measurement == null) return;
- if (context.mounted) {
- model.addAndExport(context, measurement);
- } else {
- model.add(measurement);
+ if (measurement.$1 != null) {
+ if (context.mounted) {
+ model.addAndExport(context, measurement.$1!);
+ } else {
+ model.add(measurement.$1!);
+ }
+ }
+ if (measurement.$2 != null) {
+ // TODO: save medicine intake
}
},
child: const Icon(Icons.add,),
test/ui/components/add_measurement_dialoge_test.dart
@@ -13,10 +13,10 @@ import 'settings/color_picker_list_tile_test.dart';
import 'util.dart';
void main() {
- group('AddMeasurementDialoge', () {
+ group('AddEntryDialoge', () {
testWidgets('should show everything on initial page', (widgetTester) async {
await widgetTester.pumpWidget(materialApp(
- AddMeasurementDialoge(
+ AddEntryDialoge(
settings: Settings(),
)
));
@@ -30,7 +30,7 @@ void main() {
});
testWidgets('should prefill initialRecord values', (widgetTester) async {
await widgetTester.pumpWidget(materialApp(
- AddMeasurementDialoge(
+ AddEntryDialoge(
settings: Settings(),
initialRecord: BloodPressureRecord(
DateTime.now(), 123, 56, 43, 'Test note',
@@ -50,32 +50,32 @@ void main() {
having((p0) => p0.initialColor, 'ColorSelectionListTile should have correct initial color', Colors.teal));
});
});
- group('showAddMeasurementDialoge', () {
+ group('showAddEntryDialoge', () {
testWidgets('should return null on cancel', (widgetTester) async {
dynamic result = 'not null';
await loadDialoge(widgetTester, (context) async
- => result = await showAddMeasurementDialoge(context, Settings(),
+ => result = await showAddEntryDialoge(context, Settings(),
mockRecord(sys: 123, dia: 56, pul: 43, note: 'Test note', pin: Colors.teal)));
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
await widgetTester.tap(find.byIcon(Icons.close));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsNothing);
+ expect(find.byType(AddEntryDialoge), findsNothing);
expect(result, null);
});
- testWidgets('should return values on cancel', (widgetTester) async {
+ testWidgets('should return values on edit cancel', (widgetTester) async {
dynamic result = 'not null';
final record = mockRecord(sys: 123, dia: 56, pul: 43, note: 'Test note', pin: Colors.teal);
await loadDialoge(widgetTester, (context) async
- => result = await showAddMeasurementDialoge(context, Settings(), record));
+ => result = await showAddEntryDialoge(context, Settings(), record));
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsNothing);
+ expect(find.byType(AddEntryDialoge), findsNothing);
- expect(result, isA<BloodPressureRecord>().having(
+ expect(result?.$1, isA<BloodPressureRecord>().having(
(p0) => (p0.creationTime, p0.systolic, p0.diastolic, p0.pulse, p0.notes, p0.needlePin!.color),
'should return initial values as they were not modified',
(record.creationTime, record.systolic, record.diastolic, record.pulse, record.notes, record.needlePin!.color)));
@@ -83,7 +83,7 @@ void main() {
testWidgets('should be able to input values', (WidgetTester widgetTester) async {
dynamic result = 'not null';
await loadDialoge(widgetTester, (context) async
- => result = await showAddMeasurementDialoge(context, Settings()));
+ => result = await showAddEntryDialoge(context, Settings()));
await widgetTester.enterText(find.ancestor(of: find.text('Systolic').first, matching: find.byType(TextFormField)), '123');
await widgetTester.enterText(find.ancestor(of: find.text('Diastolic').first, matching: find.byType(TextFormField)), '67');
@@ -99,19 +99,19 @@ void main() {
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(result, isA<BloodPressureRecord>());
- BloodPressureRecord castResult = result;
- expect(castResult.systolic, 123);
- expect(castResult.diastolic, 67);
- expect(castResult.pulse, 89);
- expect(castResult.notes, 'Test note');
- expect(castResult.needlePin?.color, Colors.red);
+ expect(result?.$1, isA<BloodPressureRecord>()
+ .having((p0) => p0.systolic, 'systolic', 123)
+ .having((p0) => p0.diastolic, 'diastolic', 67)
+ .having((p0) => p0.pulse, 'pulse', 89)
+ .having((p0) => p0.notes, 'notes', 'Test note')
+ .having((p0) => p0.needlePin?.color, 'needlePin', Colors.red)
+ );
});
testWidgets('should not allow invalid values', (widgetTester) async {
- await loadDialoge(widgetTester, (context) => showAddMeasurementDialoge(context, Settings()));
+ await loadDialoge(widgetTester, (context) => showAddEntryDialoge(context, Settings()));
final localizations = await AppLocalizations.delegate.load(const Locale('en'));
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
expect(find.text(localizations.errNaN), findsNothing);
expect(find.text(localizations.errLt30), findsNothing);
expect(find.text(localizations.errUnrealistic), findsNothing);
@@ -122,7 +122,7 @@ void main() {
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
expect(find.text(localizations.errNaN), findsOneWidget);
expect(find.text(localizations.errLt30), findsNothing);
expect(find.text(localizations.errUnrealistic), findsNothing);
@@ -131,7 +131,7 @@ void main() {
await widgetTester.enterText(find.ancestor(of: find.text('Pulse').first, matching: find.byType(TextFormField)), '20');
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
expect(find.text(localizations.errNaN), findsNothing);
expect(find.text(localizations.errLt30), findsOneWidget);
expect(find.text(localizations.errUnrealistic), findsNothing);
@@ -141,7 +141,7 @@ void main() {
await widgetTester.enterText(find.ancestor(of: find.text('Diastolic').first, matching: find.byType(TextFormField)), '500');
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
expect(find.text(localizations.errNaN), findsNothing);
expect(find.text(localizations.errLt30), findsNothing);
expect(find.text(localizations.errUnrealistic), findsOneWidget);
@@ -151,7 +151,7 @@ void main() {
await widgetTester.enterText(find.ancestor(of: find.text('Systolic').first, matching: find.byType(TextFormField)), '90');
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsOneWidget);
+ expect(find.byType(AddEntryDialoge), findsOneWidget);
expect(find.text(localizations.errNaN), findsNothing);
expect(find.text(localizations.errLt30), findsNothing);
expect(find.text(localizations.errUnrealistic), findsNothing);
@@ -162,7 +162,7 @@ void main() {
await widgetTester.enterText(find.ancestor(of: find.text('Systolic').first, matching: find.byType(TextFormField)), '123');
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsNothing);
+ expect(find.byType(AddEntryDialoge), findsNothing);
expect(find.text(localizations.errNaN), findsNothing);
expect(find.text(localizations.errLt30), findsNothing);
expect(find.text(localizations.errUnrealistic), findsNothing);
@@ -170,23 +170,23 @@ void main() {
});
testWidgets('should allow invalid values when setting is set', (widgetTester) async {
await loadDialoge(widgetTester, (context) =>
- showAddMeasurementDialoge(context, Settings(validateInputs: false, allowMissingValues: true)));
+ showAddEntryDialoge(context, Settings(validateInputs: false, allowMissingValues: true)));
await widgetTester.enterText(find.ancestor(of: find.text('Systolic').first, matching: find.byType(TextFormField)), '2');
await widgetTester.enterText(find.ancestor(of: find.text('Diastolic').first, matching: find.byType(TextFormField)), '500');
await widgetTester.tap(find.text('SAVE'));
await widgetTester.pumpAndSettle();
- expect(find.byType(AddMeasurementDialoge), findsNothing);
+ expect(find.byType(AddEntryDialoge), findsNothing);
});
testWidgets('should respect settings.allowManualTimeInput', (widgetTester) async {
await loadDialoge(widgetTester, (context) =>
- showAddMeasurementDialoge(context, Settings(allowManualTimeInput: false)));
+ showAddEntryDialoge(context, Settings(allowManualTimeInput: false)));
expect(find.byIcon(Icons.edit), findsNothing);
});
testWidgets('should start with sys input focused', (widgetTester) async {
await loadDialoge(widgetTester, (context) =>
- showAddMeasurementDialoge(context, Settings(), mockRecord(sys: 12)));
+ showAddEntryDialoge(context, Settings(), mockRecord(sys: 12)));
final primaryFocus = FocusManager.instance.primaryFocus;
expect(primaryFocus?.context?.widget, isNotNull);
@@ -200,7 +200,7 @@ void main() {
});
testWidgets('should focus next on input finished', (widgetTester) async {
await loadDialoge(widgetTester, (context) =>
- showAddMeasurementDialoge(context, Settings(), mockRecord(sys: 12, dia: 3, pul: 4, note: 'note')));
+ showAddEntryDialoge(context, Settings(), mockRecord(sys: 12, dia: 3, pul: 4, note: 'note')));
await widgetTester.enterText(find.ancestor(of: find.text('Systolic').first, matching: find.byType(TextFormField)), '123');
@@ -241,7 +241,7 @@ void main() {
testWidgets('should focus last input field on backspace pressed in empty input field', (widgetTester) async {
await loadDialoge(widgetTester, (context) =>
- showAddMeasurementDialoge(context, Settings(), mockRecord(sys: 12, dia: 3, pul: 4, note: 'note')));
+ showAddEntryDialoge(context, Settings(), mockRecord(sys: 12, dia: 3, pul: 4, note: 'note')));
await widgetTester.enterText(find.ancestor(of: find.text('note').first, matching: find.byType(TextFormField)), '');
@@ -299,5 +299,6 @@ void main() {
expect(fourthFocusedTextFormField, findsOneWidget);
expect(find.descendant(of: fourthFocusedTextFormField, matching: find.text('Systolic')), findsWidgets);
});
+ // TODO: test medicine_intake
});
}
\ No newline at end of file
pubspec.lock
@@ -325,6 +325,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.0"
+ leak_tracker:
+ dependency: transitive
+ description:
+ name: leak_tracker
+ sha256: "04be76c4a4bb50f14904e64749237e541e7c7bcf7ec0b196907322ab5d2fc739"
+ url: "https://pub.dev"
+ source: hosted
+ version: "9.0.16"
+ leak_tracker_testing:
+ dependency: transitive
+ description:
+ name: leak_tracker_testing
+ sha256: b06739349ec2477e943055aea30172c5c7000225f79dad4702e2ec0eda79a6ff
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.5"
lints:
dependency: transitive
description:
@@ -361,18 +377,18 @@ packages:
dependency: transitive
description:
name: material_color_utilities
- sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
+ sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
- version: "0.5.0"
+ version: "0.8.0"
meta:
dependency: transitive
description:
name: meta
- sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
+ sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
url: "https://pub.dev"
source: hosted
- version: "1.10.0"
+ version: "1.11.0"
mockito:
dependency: "direct dev"
description:
@@ -770,6 +786,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
+ url: "https://pub.dev"
+ source: hosted
+ version: "13.0.0"
watcher:
dependency: transitive
description:
@@ -782,10 +806,10 @@ packages:
dependency: transitive
description:
name: web
- sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
+ sha256: edc8a9573dd8c5a83a183dae1af2b6fd4131377404706ca4e5420474784906fa
url: "https://pub.dev"
source: hosted
- version: "0.3.0"
+ version: "0.4.0"
win32:
dependency: transitive
description: