Setup data

This commit is contained in:
LittleSheep 2024-08-15 01:26:42 +08:00
parent cb011ddcf9
commit 7797c1b635
14 changed files with 711 additions and 296 deletions

File diff suppressed because one or more lines are too long

View File

@ -3,20 +3,27 @@ PODS:
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- sqflite (0.0.3):
- Flutter
- FlutterMacOS
DEPENDENCIES: DEPENDENCIES:
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
EXTERNAL SOURCES: EXTERNAL SOURCES:
Flutter: Flutter:
:path: Flutter :path: Flutter
shared_preferences_foundation: shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin" :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite:
:path: ".symlinks/plugins/sqflite/darwin"
SPEC CHECKSUMS: SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796

View File

@ -0,0 +1,46 @@
import 'package:dietary_guard/models/food_data.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FoodDataController extends GetxController {
RxBool isReady = false.obs;
late final SharedPreferences _prefs;
Future<void> initialize(BuildContext context) async {
if (isReady.value) return;
_prefs = await SharedPreferences.getInstance();
isReady.value = true;
}
String? getApiKey() {
return _prefs.getString("data_fdc_api_key");
}
Future<void> setApiKey(String value) async {
await _prefs.setString("data_fdc_api_key", value);
}
Future<FoodDataQueryResponse> searchFood(String probe) async {
final client = Dio();
final resp = await client.get(
'https://api.nal.usda.gov/fdc/v1/foods/search',
queryParameters: {
'query': probe,
'dataType': 'Foundation',
'pageSize': 25,
'pageNumber': 1,
'sortBy': 'dataType.keyword',
'sortOrder': 'asc',
'api_key': getApiKey(),
},
);
final result = FoodDataQueryResponse.fromJson(resp.data);
return result;
}
}

View File

@ -1,6 +1,8 @@
import 'package:dietary_guard/controllers/food_data.dart';
import 'package:dietary_guard/screens/query.dart'; import 'package:dietary_guard/screens/query.dart';
import 'package:dietary_guard/screens/settings.dart'; import 'package:dietary_guard/screens/settings.dart';
import 'package:dietary_guard/shells/nav_shell.dart'; import 'package:dietary_guard/shells/nav_shell.dart';
import 'package:dietary_guard/translations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -42,9 +44,24 @@ class MyApp extends StatelessWidget {
theme: ThemeData( theme: ThemeData(
colorScheme: ColorScheme.fromSeed( colorScheme: ColorScheme.fromSeed(
seedColor: Colors.green, seedColor: Colors.green,
brightness: Brightness.light,
), ),
useMaterial3: true, useMaterial3: true,
), ),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.green,
brightness: Brightness.dark,
),
useMaterial3: true,
),
themeMode: ThemeMode.system,
translations: AppTranslations(),
onInit: () => _initializeProviders(context),
); );
} }
void _initializeProviders(BuildContext context) async {
Get.put(FoodDataController());
}
} }

402
lib/models/food_data.dart Normal file
View File

@ -0,0 +1,402 @@
class FoodDataQueryResponse {
int totalHits;
int currentPage;
int totalPages;
List<int> pageList;
FoodSearchCriteria foodSearchCriteria;
List<FoodData> foods;
Aggregations aggregations;
FoodDataQueryResponse({
required this.totalHits,
required this.currentPage,
required this.totalPages,
required this.pageList,
required this.foodSearchCriteria,
required this.foods,
required this.aggregations,
});
factory FoodDataQueryResponse.fromJson(Map<String, dynamic> json) =>
FoodDataQueryResponse(
totalHits: json["totalHits"],
currentPage: json["currentPage"],
totalPages: json["totalPages"],
pageList: List<int>.from(json["pageList"].map((x) => x)),
foodSearchCriteria:
FoodSearchCriteria.fromJson(json["foodSearchCriteria"]),
foods:
List<FoodData>.from(json["foods"].map((x) => FoodData.fromJson(x))),
aggregations: Aggregations.fromJson(json["aggregations"]),
);
Map<String, dynamic> toJson() => {
"totalHits": totalHits,
"currentPage": currentPage,
"totalPages": totalPages,
"pageList": List<dynamic>.from(pageList.map((x) => x)),
"foodSearchCriteria": foodSearchCriteria.toJson(),
"foods": List<dynamic>.from(foods.map((x) => x.toJson())),
"aggregations": aggregations.toJson(),
};
}
class Aggregations {
DataType dataType;
Nutrients nutrients;
Aggregations({
required this.dataType,
required this.nutrients,
});
factory Aggregations.fromJson(Map<String, dynamic> json) => Aggregations(
dataType: DataType.fromJson(json["dataType"]),
nutrients: Nutrients.fromJson(json["nutrients"]),
);
Map<String, dynamic> toJson() => {
"dataType": dataType.toJson(),
"nutrients": nutrients.toJson(),
};
}
class DataType {
int branded;
int surveyFndds;
int srLegacy;
int foundation;
DataType({
required this.branded,
required this.surveyFndds,
required this.srLegacy,
required this.foundation,
});
factory DataType.fromJson(Map<String, dynamic> json) => DataType(
branded: json["Branded"],
surveyFndds: json["Survey (FNDDS)"],
srLegacy: json["SR Legacy"],
foundation: json["Foundation"],
);
Map<String, dynamic> toJson() => {
"Branded": branded,
"Survey (FNDDS)": surveyFndds,
"SR Legacy": srLegacy,
"Foundation": foundation,
};
}
class Nutrients {
Nutrients();
factory Nutrients.fromJson(Map<String, dynamic> json) => Nutrients();
Map<String, dynamic> toJson() => {};
}
class FoodSearchCriteria {
List<Type> dataType;
String query;
String generalSearchInput;
int pageNumber;
String sortBy;
String sortOrder;
int numberOfResultsPerPage;
int pageSize;
bool requireAllWords;
List<Type> foodTypes;
FoodSearchCriteria({
required this.dataType,
required this.query,
required this.generalSearchInput,
required this.pageNumber,
required this.sortBy,
required this.sortOrder,
required this.numberOfResultsPerPage,
required this.pageSize,
required this.requireAllWords,
required this.foodTypes,
});
factory FoodSearchCriteria.fromJson(Map<String, dynamic> json) =>
FoodSearchCriteria(
dataType:
List<Type>.from(json["dataType"].map((x) => typeValues.map[x]!)),
query: json["query"],
generalSearchInput: json["generalSearchInput"],
pageNumber: json["pageNumber"],
sortBy: json["sortBy"],
sortOrder: json["sortOrder"],
numberOfResultsPerPage: json["numberOfResultsPerPage"],
pageSize: json["pageSize"],
requireAllWords: json["requireAllWords"],
foodTypes:
List<Type>.from(json["foodTypes"].map((x) => typeValues.map[x]!)),
);
Map<String, dynamic> toJson() => {
"dataType":
List<dynamic>.from(dataType.map((x) => typeValues.reverse[x])),
"query": query,
"generalSearchInput": generalSearchInput,
"pageNumber": pageNumber,
"sortBy": sortBy,
"sortOrder": sortOrder,
"numberOfResultsPerPage": numberOfResultsPerPage,
"pageSize": pageSize,
"requireAllWords": requireAllWords,
"foodTypes":
List<dynamic>.from(foodTypes.map((x) => typeValues.reverse[x])),
};
}
enum Type { FOUNDATION, SR_LEGACY }
final typeValues =
EnumValues({"Foundation": Type.FOUNDATION, "SR Legacy": Type.SR_LEGACY});
class FoodData {
int fdcId;
String description;
String commonNames;
String additionalDescriptions;
Type dataType;
int ndbNumber;
DateTime publishedDate;
FoodCategory? foodCategory;
DateTime? mostRecentAcquisitionDate;
String allHighlightFields;
double score;
List<dynamic> microbes;
List<FoodNutrient> foodNutrients;
List<dynamic> finalFoodInputFoods;
List<dynamic> foodMeasures;
List<dynamic> foodAttributes;
List<dynamic> foodAttributeTypes;
List<dynamic> foodVersionIds;
FoodData({
required this.fdcId,
required this.description,
required this.commonNames,
required this.additionalDescriptions,
required this.dataType,
required this.ndbNumber,
required this.publishedDate,
required this.foodCategory,
this.mostRecentAcquisitionDate,
required this.allHighlightFields,
required this.score,
required this.microbes,
required this.foodNutrients,
required this.finalFoodInputFoods,
required this.foodMeasures,
required this.foodAttributes,
required this.foodAttributeTypes,
required this.foodVersionIds,
});
factory FoodData.fromJson(Map<String, dynamic> json) => FoodData(
fdcId: json["fdcId"],
description: json["description"],
commonNames: json["commonNames"],
additionalDescriptions: json["additionalDescriptions"],
dataType: typeValues.map[json["dataType"]]!,
ndbNumber: json["ndbNumber"],
publishedDate: DateTime.parse(json["publishedDate"]),
foodCategory: foodCategoryValues.map[json["foodCategory"]],
mostRecentAcquisitionDate: json["mostRecentAcquisitionDate"] == null
? null
: DateTime.parse(json["mostRecentAcquisitionDate"]),
allHighlightFields: json["allHighlightFields"],
score: json["score"]?.toDouble(),
microbes: List<dynamic>.from(json["microbes"].map((x) => x)),
foodNutrients: List<FoodNutrient>.from(
json["foodNutrients"].map((x) => FoodNutrient.fromJson(x))),
finalFoodInputFoods:
List<dynamic>.from(json["finalFoodInputFoods"].map((x) => x)),
foodMeasures: List<dynamic>.from(json["foodMeasures"].map((x) => x)),
foodAttributes:
List<dynamic>.from(json["foodAttributes"].map((x) => x)),
foodAttributeTypes:
List<dynamic>.from(json["foodAttributeTypes"].map((x) => x)),
foodVersionIds:
List<dynamic>.from(json["foodVersionIds"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"fdcId": fdcId,
"description": description,
"commonNames": commonNames,
"additionalDescriptions": additionalDescriptions,
"dataType": typeValues.reverse[dataType],
"ndbNumber": ndbNumber,
"publishedDate":
"${publishedDate.year.toString().padLeft(4, '0')}-${publishedDate.month.toString().padLeft(2, '0')}-${publishedDate.day.toString().padLeft(2, '0')}",
"foodCategory": foodCategoryValues.reverse[foodCategory],
"mostRecentAcquisitionDate":
"${mostRecentAcquisitionDate!.year.toString().padLeft(4, '0')}-${mostRecentAcquisitionDate!.month.toString().padLeft(2, '0')}-${mostRecentAcquisitionDate!.day.toString().padLeft(2, '0')}",
"allHighlightFields": allHighlightFields,
"score": score,
"microbes": List<dynamic>.from(microbes.map((x) => x)),
"foodNutrients":
List<dynamic>.from(foodNutrients.map((x) => x.toJson())),
"finalFoodInputFoods":
List<dynamic>.from(finalFoodInputFoods.map((x) => x)),
"foodMeasures": List<dynamic>.from(foodMeasures.map((x) => x)),
"foodAttributes": List<dynamic>.from(foodAttributes.map((x) => x)),
"foodAttributeTypes":
List<dynamic>.from(foodAttributeTypes.map((x) => x)),
"foodVersionIds": List<dynamic>.from(foodVersionIds.map((x) => x)),
};
}
enum FoodCategory { DAIRY_AND_EGG_PRODUCTS }
final foodCategoryValues =
EnumValues({"Dairy and Egg Products": FoodCategory.DAIRY_AND_EGG_PRODUCTS});
class FoodNutrient {
int nutrientId;
String nutrientName;
String nutrientNumber;
UnitName unitName;
DerivationCode? derivationCode;
String? derivationDescription;
int? derivationId;
double? value;
int? foodNutrientSourceId;
String? foodNutrientSourceCode;
FoodNutrientSourceDescription? foodNutrientSourceDescription;
int rank;
int indentLevel;
int foodNutrientId;
int? dataPoints;
double? min;
double? max;
double? median;
FoodNutrient({
required this.nutrientId,
required this.nutrientName,
required this.nutrientNumber,
required this.unitName,
this.derivationCode,
this.derivationDescription,
this.derivationId,
this.value,
this.foodNutrientSourceId,
this.foodNutrientSourceCode,
this.foodNutrientSourceDescription,
required this.rank,
required this.indentLevel,
required this.foodNutrientId,
this.dataPoints,
this.min,
this.max,
this.median,
});
factory FoodNutrient.fromJson(Map<String, dynamic> json) => FoodNutrient(
nutrientId: json["nutrientId"],
nutrientName: json["nutrientName"],
nutrientNumber: json["nutrientNumber"],
unitName: unitNameValues.map[json["unitName"]]!,
derivationCode: derivationCodeValues.map[json["derivationCode"]]!,
derivationDescription: json["derivationDescription"],
derivationId: json["derivationId"],
value: json["value"]?.toDouble(),
foodNutrientSourceId: json["foodNutrientSourceId"],
foodNutrientSourceCode: json["foodNutrientSourceCode"],
foodNutrientSourceDescription: foodNutrientSourceDescriptionValues
.map[json["foodNutrientSourceDescription"]]!,
rank: json["rank"],
indentLevel: json["indentLevel"],
foodNutrientId: json["foodNutrientId"],
dataPoints: json["dataPoints"],
min: json["min"]?.toDouble(),
max: json["max"]?.toDouble(),
median: json["median"]?.toDouble(),
);
Map<String, dynamic> toJson() => {
"nutrientId": nutrientId,
"nutrientName": nutrientName,
"nutrientNumber": nutrientNumber,
"unitName": unitNameValues.reverse[unitName],
"derivationCode": derivationCodeValues.reverse[derivationCode],
"derivationDescription": derivationDescription,
"derivationId": derivationId,
"value": value,
"foodNutrientSourceId": foodNutrientSourceId,
"foodNutrientSourceCode": foodNutrientSourceCode,
"foodNutrientSourceDescription": foodNutrientSourceDescriptionValues
.reverse[foodNutrientSourceDescription],
"rank": rank,
"indentLevel": indentLevel,
"foodNutrientId": foodNutrientId,
"dataPoints": dataPoints,
"min": min,
"max": max,
"median": median,
};
}
enum DerivationCode { A, AS, BFFN, BFNN, BFZN, CAZN, LC, NC, NR, T, Z }
final derivationCodeValues = EnumValues({
"A": DerivationCode.A,
"AS": DerivationCode.AS,
"BFFN": DerivationCode.BFFN,
"BFNN": DerivationCode.BFNN,
"BFZN": DerivationCode.BFZN,
"CAZN": DerivationCode.CAZN,
"LC": DerivationCode.LC,
"NC": DerivationCode.NC,
"NR": DerivationCode.NR,
"T": DerivationCode.T,
"Z": DerivationCode.Z
});
enum FoodNutrientSourceDescription {
ANALYTICAL_OR_DERIVED_FROM_ANALYTICAL,
ASSUMED_ZERO,
CALCULATED_FROM_NUTRIENT_LABEL_BY_NDL,
CALCULATED_OR_IMPUTED
}
final foodNutrientSourceDescriptionValues = EnumValues({
"Analytical or derived from analytical":
FoodNutrientSourceDescription.ANALYTICAL_OR_DERIVED_FROM_ANALYTICAL,
"Assumed zero": FoodNutrientSourceDescription.ASSUMED_ZERO,
"Calculated from nutrient label by NDL":
FoodNutrientSourceDescription.CALCULATED_FROM_NUTRIENT_LABEL_BY_NDL,
"Calculated or imputed": FoodNutrientSourceDescription.CALCULATED_OR_IMPUTED
});
enum UnitName { G, IU, KCAL, K_J, MG, UG }
final unitNameValues = EnumValues({
"G": UnitName.G,
"IU": UnitName.IU,
"KCAL": UnitName.KCAL,
"kJ": UnitName.K_J,
"MG": UnitName.MG,
"UG": UnitName.UG
});
class EnumValues<T> {
Map<String, T> map;
late Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
reverseMap = map.map((k, v) => MapEntry(v, k));
return reverseMap;
}
}

View File

@ -1,10 +1,84 @@
import 'package:dietary_guard/controllers/food_data.dart';
import 'package:dietary_guard/models/food_data.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
class QueryScreen extends StatelessWidget { class QueryScreen extends StatefulWidget {
const QueryScreen({super.key}); const QueryScreen({super.key});
@override
State<QueryScreen> createState() => _QueryScreenState();
}
class _QueryScreenState extends State<QueryScreen> {
bool _isLoading = false;
int _totalCount = 0;
List<FoodData> _foodData = List.empty();
Future<void> _searchFood(String probe) async {
if (_isLoading) return;
setState(() => _isLoading = true);
final FoodDataController data = Get.find();
if (data.getApiKey() == null) return;
final result = await data.searchFood(probe);
setState(() {
_totalCount = result.totalHits;
_foodData = result.foods;
_isLoading = false;
});
}
@override
void initState() {
super.initState();
final FoodDataController data = Get.find();
data.initialize(context);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const SizedBox(); return SafeArea(
child: Column(
children: [
SearchBar(
padding: const WidgetStatePropertyAll<EdgeInsets>(
EdgeInsets.symmetric(horizontal: 16.0),
),
onSubmitted: (value) {
_searchFood(value);
},
leading: const Icon(Icons.search),
).paddingSymmetric(horizontal: 24),
if (_isLoading)
const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 3),
).paddingSymmetric(vertical: 16)
else
Expanded(
child: ListView.builder(
itemCount: _foodData.length,
itemBuilder: (context, index) {
final item = _foodData[index];
return ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
title: Text(item.description),
subtitle: Text(
DateFormat("yyyy-MM-dd").format(item.publishedDate),
),
);
},
).paddingOnly(top: 8),
),
],
),
);
} }
} }

View File

@ -1,10 +1,70 @@
import 'package:dietary_guard/controllers/food_data.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
class SettingsScreen extends StatelessWidget { class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key}); const SettingsScreen({super.key});
@override
State<SettingsScreen> createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
final TextEditingController _fdcApiKeyController = TextEditingController();
Future<void> _applySettings() async {
final FoodDataController data = Get.find();
await data.setApiKey(_fdcApiKeyController.text);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('settingsApplied'.tr),
));
}
@override
void initState() {
final FoodDataController data = Get.find();
_fdcApiKeyController.text = data.getApiKey() ?? '';
super.initState();
}
@override
void dispose() {
_fdcApiKeyController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Placeholder(); return Scaffold(
appBar: AppBar(
title: Text('settings'.tr),
),
body: ListView(
children: [
const SizedBox(height: 8),
TextField(
controller: _fdcApiKeyController,
obscureText: true,
decoration: const InputDecoration(
border: OutlineInputBorder(),
label: Text("FDC API Key"),
isDense: true,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton.icon(
icon: const Icon(Icons.save, size: 16),
label: Text('apply'.tr),
onPressed: () => _applySettings(),
),
],
).paddingSymmetric(vertical: 12),
],
).paddingSymmetric(horizontal: 24),
);
} }
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
class Destination { class Destination {
@ -21,8 +22,8 @@ class _NavShellState extends State<NavShell> {
int _focusDestination = 0; int _focusDestination = 0;
final List<Destination> _allDestinations = <Destination>[ final List<Destination> _allDestinations = <Destination>[
const Destination('Query', 'query', Icons.search), Destination('query'.tr, 'query', Icons.search),
const Destination('Settings', 'settings', Icons.settings) Destination('settings'.tr, 'settings', Icons.settings)
]; ];
@override @override

11
lib/translations.dart Normal file
View File

@ -0,0 +1,11 @@
import 'package:dietary_guard/translations/en_us.dart';
import 'package:dietary_guard/translations/zh_cn.dart';
import 'package:get/get.dart';
class AppTranslations extends Translations {
@override
Map<String, Map<String, String>> get keys => {
'en_US': i18nEnglish,
'zh_CN': i18nSimplifiedChinese,
};
}

View File

@ -0,0 +1,8 @@
const i18nEnglish = {
'query': 'Query',
'settings': 'Settings',
'preparingData': 'Preparing data...',
'settingsApplied': 'Settings Applied',
'apply': 'Apply',
'searchHistoryNotIncluded': 'Search History not Included, yet',
};

View File

@ -0,0 +1,8 @@
const i18nSimplifiedChinese = {
'query': '查询',
'settings': '设置',
'preparingData': '准备数据中…',
'settingsApplied': '设置已应用',
'apply': '应用',
'searchHistoryNotIncluded': '搜索记录还没实现',
};

View File

@ -6,7 +6,9 @@ import FlutterMacOS
import Foundation import Foundation
import shared_preferences_foundation import shared_preferences_foundation
import sqflite
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
} }

View File

@ -49,6 +49,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.8" version: "1.0.8"
dio:
dependency: "direct main"
description:
name: dio
sha256: "0dfb6b6a1979dac1c1245e17cef824d7b452ea29bd33d3467269f9bef3715fb0"
url: "https://pub.dev"
source: hosted
version: "5.6.0"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -112,6 +128,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.3" version: "14.2.3"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
intl:
dependency: "direct main"
description:
name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
version: "0.19.0"
leak_tracker: leak_tracker:
dependency: transitive dependency: transitive
description: description:
@ -293,6 +325,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.10.0"
sqflite:
dependency: "direct main"
description:
name: sqflite
sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d
url: "https://pub.dev"
source: hosted
version: "2.3.3+1"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
sha256: c5e5b2a142a893a752cb36ae5888680248686725a54afceff31f9a3a76bc53c2
url: "https://pub.dev"
source: hosted
version: "2.5.4+1"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -317,6 +365,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -333,6 +389,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2" version: "0.7.2"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:

View File

@ -38,6 +38,9 @@ dependencies:
get: ^4.6.6 get: ^4.6.6
go_router: ^14.2.3 go_router: ^14.2.3
shared_preferences: ^2.3.1 shared_preferences: ^2.3.1
sqflite: ^2.3.3+1
dio: ^5.6.0
intl: ^0.19.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -62,8 +65,8 @@ flutter:
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
assets: # assets:
- assets/data/ # - assets/data/
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images # https://flutter.dev/to/resolution-aware-images