Merge pull request 'Implement food entry lookup on entering a food name.' (#1) from food-suggestion into master
Reviewed-on: marco/calodiary#1
This commit is contained in:
commit
131f39c1c8
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:calodiary/storage/storage.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:calodiary/food_entry_bloc.dart';
|
import 'package:calodiary/food_entry_bloc.dart';
|
||||||
import 'package:calodiary/row_with_spacers_widget.dart';
|
import 'package:calodiary/row_with_spacers_widget.dart';
|
||||||
@ -16,22 +19,53 @@ class _EnterFoodWidgetState extends State<EnterFoodWidget> {
|
|||||||
TextEditingController nameController = TextEditingController();
|
TextEditingController nameController = TextEditingController();
|
||||||
TextEditingController massController = TextEditingController();
|
TextEditingController massController = TextEditingController();
|
||||||
TextEditingController kcalPerMassController = TextEditingController();
|
TextEditingController kcalPerMassController = TextEditingController();
|
||||||
|
Map<String, double> suggestions = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
suggestions = FoodStorage.getInstance().getFoodEntryLookupDatabase;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var nameWidget = TextField(
|
var nameWidget = Autocomplete<String>(
|
||||||
decoration: const InputDecoration(hintText: "Name"),
|
optionsViewOpenDirection: OptionsViewOpenDirection.down,
|
||||||
controller: nameController,
|
fieldViewBuilder: (context, controller, focusNode, onSubmitted) {
|
||||||
);
|
nameController = controller;
|
||||||
|
return TextFormField(
|
||||||
|
controller: controller,
|
||||||
|
focusNode: focusNode,
|
||||||
|
decoration: const InputDecoration(label: Text("Name")));
|
||||||
|
},
|
||||||
|
optionsBuilder: (TextEditingValue textEditingValue) {
|
||||||
|
if (textEditingValue.text == '') {
|
||||||
|
return const Iterable<String>.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return suggestions.keys.where(
|
||||||
|
(name) {
|
||||||
|
return name
|
||||||
|
.toLowerCase()
|
||||||
|
.contains(textEditingValue.text.toLowerCase());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onSelected: (selectedFood) {
|
||||||
|
double kcalPerMassForSelectedFood = suggestions[selectedFood]!;
|
||||||
|
setState(() {
|
||||||
|
kcalPerMassController.text = kcalPerMassForSelectedFood.toString();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var massWidget = TextField(
|
var massWidget = TextField(
|
||||||
decoration: const InputDecoration(hintText: "Menge"),
|
decoration: const InputDecoration(label: Text("Menge")),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
controller: massController,
|
controller: massController,
|
||||||
);
|
);
|
||||||
|
|
||||||
var kcalPerMassWidget = TextField(
|
var kcalPerMassWidget = TextField(
|
||||||
decoration: const InputDecoration(hintText: "kcal pro 100g"),
|
decoration: const InputDecoration(label: Text("kcal pro")),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
controller: kcalPerMassController);
|
controller: kcalPerMassController);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import 'package:uuid/uuid.dart';
|
|||||||
|
|
||||||
class FoodEntryBloc extends Bloc<FoodEvent, FoodEntryState> {
|
class FoodEntryBloc extends Bloc<FoodEvent, FoodEntryState> {
|
||||||
final FoodEntryState initialState;
|
final FoodEntryState initialState;
|
||||||
final AppStorage storage;
|
final FoodStorage storage;
|
||||||
final DateTime forDate;
|
final DateTime forDate;
|
||||||
|
|
||||||
FoodEntryBloc(
|
FoodEntryBloc(
|
||||||
@ -12,16 +12,18 @@ class FoodEntryBloc extends Bloc<FoodEvent, FoodEntryState> {
|
|||||||
required this.forDate,
|
required this.forDate,
|
||||||
required this.storage})
|
required this.storage})
|
||||||
: super(initialState) {
|
: super(initialState) {
|
||||||
on<FoodEntryEvent>(addFoodEntry);
|
on<FoodEntryEvent>(handleFoodEntryEvent);
|
||||||
on<FoodDeletionEvent>(deleteFood);
|
on<FoodDeletionEvent>(deleteFood);
|
||||||
on<PageChangedEvent>(updateEntries);
|
on<PageChangedEvent>(updateEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFoodEntry(FoodEntryEvent event, Emitter<FoodEntryState> emit) async {
|
void handleFoodEntryEvent(
|
||||||
|
FoodEntryEvent event, Emitter<FoodEntryState> emit) async {
|
||||||
FoodEntryState newState = FoodEntryState.from(state);
|
FoodEntryState newState = FoodEntryState.from(state);
|
||||||
newState.addEntry(event.entry);
|
newState.addEntry(event.entry);
|
||||||
|
|
||||||
await storage.writeEntriesForDate(forDate, newState.foodEntries);
|
await storage.writeEntriesForDate(forDate, newState.foodEntries);
|
||||||
|
storage.addFoodEntryToLookupDatabase(event.entry);
|
||||||
|
|
||||||
emit(newState);
|
emit(newState);
|
||||||
}
|
}
|
||||||
|
@ -4,27 +4,34 @@ import 'package:calodiary/row_with_spacers_widget.dart';
|
|||||||
|
|
||||||
class FoodEntryWidget extends StatelessWidget {
|
class FoodEntryWidget extends StatelessWidget {
|
||||||
final FoodEntry entry;
|
final FoodEntry entry;
|
||||||
final Function(BuildContext context) onDelete;
|
final Function(BuildContext context, String id) onDelete;
|
||||||
|
|
||||||
const FoodEntryWidget(
|
const FoodEntryWidget(
|
||||||
{super.key, required this.entry, required this.onDelete});
|
{super.key, required this.entry, required this.onDelete});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Card(
|
return Dismissible(
|
||||||
child: Padding(
|
key: ValueKey(entry.id),
|
||||||
padding: const EdgeInsets.only(left: 4.0),
|
onDismissed: (direction) {
|
||||||
child: RowWidget(
|
onDelete(context, entry.id);
|
||||||
Text(entry.name),
|
},
|
||||||
Text(entry.mass.ceil().toString()),
|
child: Card(
|
||||||
Text(entry.kcalPerMass.ceil().toString()),
|
elevation: 5.0,
|
||||||
Text((entry.mass * entry.kcalPerMass / 100).ceil().toString()),
|
child: Padding(
|
||||||
IconButton(
|
padding: const EdgeInsets.only(left: 4.0),
|
||||||
style: IconButton.styleFrom(padding: EdgeInsets.zero),
|
child: RowWidget(
|
||||||
onPressed: () {
|
Text(entry.name),
|
||||||
onDelete(context);
|
Text(entry.mass.ceil().toString()),
|
||||||
},
|
Text(entry.kcalPerMass.ceil().toString()),
|
||||||
icon: const Icon(Icons.delete_forever_rounded)),
|
Text((entry.mass * entry.kcalPerMass / 100).ceil().toString()),
|
||||||
|
IconButton(
|
||||||
|
style: IconButton.styleFrom(padding: EdgeInsets.zero),
|
||||||
|
onPressed: () {
|
||||||
|
onDelete(context, entry.id);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.delete_forever_rounded)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -10,7 +10,8 @@ import 'package:go_router/go_router.dart';
|
|||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
var storage = await AppStorage.create();
|
var storage = await FoodStorage.create();
|
||||||
|
await storage.buildFoodLookupDatabase();
|
||||||
var kcalLimit = await storage.readLimit();
|
var kcalLimit = await storage.readLimit();
|
||||||
var brightness = await storage.readBrightness();
|
var brightness = await storage.readBrightness();
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ void main() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MainApp extends StatelessWidget {
|
class MainApp extends StatelessWidget {
|
||||||
final AppStorage storage;
|
final FoodStorage storage;
|
||||||
final double kcalLimit;
|
final double kcalLimit;
|
||||||
final String brightness;
|
final String brightness;
|
||||||
|
|
||||||
@ -36,38 +37,41 @@ class MainApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MultiBlocProvider(
|
return SafeArea(
|
||||||
providers: [
|
child: MultiBlocProvider(
|
||||||
BlocProvider(
|
providers: [
|
||||||
create: (context) => SettingsDataBloc(
|
BlocProvider(
|
||||||
SettingsState(kcalLimit: kcalLimit),
|
create: (context) => SettingsDataBloc(
|
||||||
storage: storage),
|
SettingsState(kcalLimit: kcalLimit),
|
||||||
),
|
storage: storage),
|
||||||
BlocProvider(
|
),
|
||||||
create: (context) => ThemeDataBloc(ThemeState(brightness: brightness),
|
BlocProvider(
|
||||||
storage: storage),
|
create: (context) => ThemeDataBloc(
|
||||||
),
|
ThemeState(brightness: brightness),
|
||||||
],
|
storage: storage),
|
||||||
child: BlocBuilder<ThemeDataBloc, ThemeState>(
|
),
|
||||||
builder: (context, state) {
|
],
|
||||||
var switchToTheme = ThemeData.light();
|
child: BlocBuilder<ThemeDataBloc, ThemeState>(
|
||||||
if (state.brightness == 'dark') {
|
builder: (context, state) {
|
||||||
switchToTheme = ThemeData.dark();
|
var switchToTheme = ThemeData.light();
|
||||||
}
|
if (state.brightness == 'dark') {
|
||||||
|
switchToTheme = ThemeData.dark();
|
||||||
|
}
|
||||||
|
|
||||||
return MaterialApp.router(
|
return MaterialApp.router(
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
GlobalWidgetsLocalizations.delegate,
|
GlobalWidgetsLocalizations.delegate,
|
||||||
GlobalCupertinoLocalizations.delegate,
|
GlobalCupertinoLocalizations.delegate,
|
||||||
],
|
],
|
||||||
supportedLocales: const [
|
supportedLocales: const [
|
||||||
Locale('de'),
|
Locale('de'),
|
||||||
],
|
],
|
||||||
theme: switchToTheme,
|
theme: switchToTheme,
|
||||||
routerConfig: router,
|
routerConfig: router,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class PerDateWidget extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PerDateWidgetState extends State<PerDateWidget> {
|
class _PerDateWidgetState extends State<PerDateWidget> {
|
||||||
late AppStorage storage;
|
late FoodStorage storage;
|
||||||
late Future<List<FoodEntry>> entriesFuture;
|
late Future<List<FoodEntry>> entriesFuture;
|
||||||
late List<FoodEntry> entries;
|
late List<FoodEntry> entries;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ class _PerDateWidgetState extends State<PerDateWidget> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
storage = AppStorage.getInstance();
|
storage = FoodStorage.getInstance();
|
||||||
entriesFuture = storage.getEntriesForDate(widget.date);
|
entriesFuture = storage.getEntriesForDate(widget.date);
|
||||||
entriesFuture.then((val) {
|
entriesFuture.then((val) {
|
||||||
entries = val;
|
entries = val;
|
||||||
@ -93,15 +93,20 @@ class _PerDateWidgetState extends State<PerDateWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return FoodEntryWidget(
|
return Column(
|
||||||
entry: state.foodEntries[index],
|
children: [
|
||||||
onDelete: (callbackContext) {
|
FoodEntryWidget(
|
||||||
callbackContext
|
entry: state.foodEntries[index],
|
||||||
.read<FoodEntryBloc>()
|
onDelete: (callbackContext, id) {
|
||||||
.add(FoodDeletionEvent(
|
callbackContext
|
||||||
entryID: state.foodEntries[index].id,
|
.read<FoodEntryBloc>()
|
||||||
));
|
.add(FoodDeletionEvent(
|
||||||
},
|
entryID: id,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:calodiary/storage/storage.dart';
|
import 'package:calodiary/storage/storage.dart';
|
||||||
|
|
||||||
class SettingsDataBloc extends Bloc<SettingsEvent, SettingsState> {
|
class SettingsDataBloc extends Bloc<SettingsEvent, SettingsState> {
|
||||||
final AppStorage storage;
|
final FoodStorage storage;
|
||||||
|
|
||||||
SettingsDataBloc(super.initialState, {required this.storage}) {
|
SettingsDataBloc(super.initialState, {required this.storage}) {
|
||||||
on<DailyKcalLimitUpdated>(persistDailyLimit);
|
on<DailyKcalLimitUpdated>(persistDailyLimit);
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:calodiary/food_entry_bloc.dart';
|
import 'package:calodiary/food_entry_bloc.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:universal_platform/universal_platform.dart';
|
import 'package:universal_platform/universal_platform.dart';
|
||||||
|
|
||||||
class AppStorage {
|
class FoodStorage {
|
||||||
static late AppStorage _instance;
|
static late FoodStorage _instance;
|
||||||
late String path;
|
late String path;
|
||||||
AppStorage._create();
|
late Map<String, double> _foodLookupDatabase = {};
|
||||||
|
|
||||||
static Future<AppStorage> create() async {
|
FoodStorage._create();
|
||||||
var storage = AppStorage._create();
|
|
||||||
|
static Future<FoodStorage> create() async {
|
||||||
|
var storage = FoodStorage._create();
|
||||||
|
|
||||||
Directory dir = Directory('');
|
Directory dir = Directory('');
|
||||||
|
|
||||||
@ -26,7 +29,7 @@ class AppStorage {
|
|||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AppStorage getInstance() => _instance;
|
static FoodStorage getInstance() => _instance;
|
||||||
|
|
||||||
Future<List<FoodEntry>> getEntriesForDate(DateTime date) async {
|
Future<List<FoodEntry>> getEntriesForDate(DateTime date) async {
|
||||||
List<FoodEntry> entries = [];
|
List<FoodEntry> entries = [];
|
||||||
@ -132,4 +135,32 @@ class AppStorage {
|
|||||||
|
|
||||||
await file.writeAsString(brightness);
|
await file.writeAsString(brightness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> buildFoodLookupDatabase() async {
|
||||||
|
// get a list of dates of the last 365 days
|
||||||
|
var dates = List<DateTime>.generate(365, (idx) {
|
||||||
|
var pastDay = Duration(days: idx);
|
||||||
|
return DateTime.now().subtract(pastDay);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var date in dates) {
|
||||||
|
addFoodEntryToLookupDatabaseFor(date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addFoodEntryToLookupDatabaseFor(DateTime date) async {
|
||||||
|
var entriesForDate = await getEntriesForDate(date);
|
||||||
|
|
||||||
|
for (var entry in entriesForDate) {
|
||||||
|
_foodLookupDatabase[entry.name] = entry.kcalPerMass;
|
||||||
|
log("Added entry: ${entry.name}/${entry.kcalPerMass}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFoodEntryToLookupDatabase(FoodEntry entry) {
|
||||||
|
_foodLookupDatabase[entry.name] = entry.kcalPerMass;
|
||||||
|
log("Added entry: ${entry.name}/${entry.kcalPerMass}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, double> get getFoodEntryLookupDatabase => _foodLookupDatabase;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import 'package:calodiary/storage/storage.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class ThemeDataBloc extends Bloc<ThemeToggleEvent, ThemeState> {
|
class ThemeDataBloc extends Bloc<ThemeToggleEvent, ThemeState> {
|
||||||
final AppStorage storage;
|
final FoodStorage storage;
|
||||||
|
|
||||||
ThemeDataBloc(super.initialState, {required this.storage}) {
|
ThemeDataBloc(super.initialState, {required this.storage}) {
|
||||||
on<ThemeToggleEvent>(switchTheme);
|
on<ThemeToggleEvent>(switchTheme);
|
||||||
|
48
pubspec.lock
48
pubspec.lock
@ -53,10 +53,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
|
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.5"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -69,10 +69,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.3"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -121,10 +121,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: cdae1b9c8bd7efadcef6112e81c903662ef2ce105cbd220a04bbb7c3425b5554
|
sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.0"
|
version: "14.2.7"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -193,10 +193,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b"
|
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.14.0"
|
version: "1.15.0"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -217,18 +217,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.4"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
|
sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.5"
|
version: "2.2.10"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -257,10 +257,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.3.0"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -350,10 +350,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794"
|
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.1"
|
version: "0.7.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -374,10 +374,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8"
|
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.5.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -390,18 +390,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: "7475cb4dd713d57b6f7464c0e13f06da0d535d8b2067e188962a59bac2cf280b"
|
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.2"
|
version: "14.2.5"
|
||||||
win32:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: win32
|
|
||||||
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.5.1"
|
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
Loading…
Reference in New Issue
Block a user