From 8cc19f0dc92d0c110eab52d0956aa378008e1018 Mon Sep 17 00:00:00 2001 From: hmalik144 Date: Mon, 19 Sep 2022 22:13:37 +0100 Subject: [PATCH] Removal of api key Network calls, integration of retrofit api added backup api --- lib/BaseStatelessWidget.dart | 5 +- lib/BaseViewModel.dart | 8 + lib/Home.dart | 8 +- lib/MainViewModel.dart | 24 +- lib/Utils/currencyUtils.dart | 6 + lib/data/model/Currency.dart | 11 + lib/data/network/backupCurrencyApi.dart | 35 +++ lib/data/network/currencyApi.dart | 54 ++++ lib/data/network/safeApiCall.dart | 30 +++ lib/data/prefs/PreferenceProvider.dart | 2 - lib/data/repository/Repository.dart | 2 + lib/data/repository/RepositoryImpl.dart | 29 ++- lib/locator.dart | 8 +- lib/main.dart | 7 + pubspec.lock | 322 ++++++++++++++++++++++++ pubspec.yaml | 9 +- 16 files changed, 548 insertions(+), 12 deletions(-) create mode 100644 lib/Utils/currencyUtils.dart create mode 100644 lib/data/model/Currency.dart create mode 100644 lib/data/network/backupCurrencyApi.dart create mode 100644 lib/data/network/currencyApi.dart create mode 100644 lib/data/network/safeApiCall.dart diff --git a/lib/BaseStatelessWidget.dart b/lib/BaseStatelessWidget.dart index 8917518..406bf20 100644 --- a/lib/BaseStatelessWidget.dart +++ b/lib/BaseStatelessWidget.dart @@ -1,6 +1,6 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:toast/toast.dart'; import 'BaseViewModel.dart'; import 'Utils/Constants.dart'; @@ -17,6 +17,7 @@ abstract class BaseStatelessWidget @override Widget build(BuildContext parent) { + ToastContext().init(parent); return Scaffold( body: Container( padding: const EdgeInsets.all(paddingGlobal), @@ -48,7 +49,7 @@ abstract class BaseStatelessWidget ); } - void onModelReady(model) {} + void onModelReady(T model) {} void onStarted() {} } diff --git a/lib/BaseViewModel.dart b/lib/BaseViewModel.dart index 0a09c6d..f41095e 100644 --- a/lib/BaseViewModel.dart +++ b/lib/BaseViewModel.dart @@ -21,4 +21,12 @@ abstract class BaseViewmodel extends BaseViewModel{ _viewState = HasError(error); notifyListeners(); } + + dynamic getData() { + if (viewState.runtimeType is HasData) { + return (viewState as HasData).data; + } else { + return null; + } + } } \ No newline at end of file diff --git a/lib/Home.dart b/lib/Home.dart index abca767..aa84cae 100644 --- a/lib/Home.dart +++ b/lib/Home.dart @@ -4,7 +4,6 @@ import 'package:easy_cc_flutter/views/DropDownBox.dart'; import 'package:easy_cc_flutter/views/EditText.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/src/widgets/framework.dart'; import 'BaseStatelessWidget.dart'; import 'Utils/Constants.dart'; @@ -57,4 +56,11 @@ class HomePage extends BaseStatelessWidget { ], ); } + + @override + void onModelReady(MainViewModel model) { + String selected1 = model.getConversionPair(SelectionType.conversionFrom); + String selected2 = model.getConversionPair(SelectionType.conversionTo); + model.setCurrencyRate(selected1, selected2); + } } diff --git a/lib/MainViewModel.dart b/lib/MainViewModel.dart index 7eb998c..2a04bb8 100644 --- a/lib/MainViewModel.dart +++ b/lib/MainViewModel.dart @@ -10,16 +10,20 @@ import 'locator.dart'; class MainViewModel extends BaseViewmodel { final Repository _repository = locator(); - double conversionRate = 1.4; + double conversionRate = 1.0; String getConversionPair(SelectionType type) { CurrencyPair pair = _repository.getConversionPair(); switch (type) { case SelectionType.conversionFrom: - return pair.currencyOne != null ? pair.currencyOne! : listOfCurrencies[0]; + return pair.currencyOne != null + ? pair.currencyOne! + : listOfCurrencies[0]; case SelectionType.conversionTo: - return pair.currencyTwo != null ? pair.currencyTwo! : listOfCurrencies[0]; + return pair.currencyTwo != null + ? pair.currencyTwo! + : listOfCurrencies[0]; default: throw NullThrownError(); } @@ -27,6 +31,18 @@ class MainViewModel extends BaseViewmodel { void setConversionPair(String fromCurrency, String toCurrency) { _repository.setConversionPair(fromCurrency, toCurrency); + setCurrencyRate(fromCurrency, toCurrency); + } + + void setCurrencyRate(String fromCurrency, String toCurrency) { + onStart(); + _repository.getConversationRateFromApi(fromCurrency, toCurrency).then( + (value) { + conversionRate = value.rate != null ? value.rate! : 0.00; + onSuccess(value); + }, onError: (exception, _) { + onError(exception.message); + }); } String convertInput(String? input, SelectionType type) { @@ -42,4 +58,4 @@ class MainViewModel extends BaseViewmodel { return (convertedInput / conversionRate).toStringAsFixed(2); } } -} \ No newline at end of file +} diff --git a/lib/Utils/currencyUtils.dart b/lib/Utils/currencyUtils.dart new file mode 100644 index 0000000..8c424cf --- /dev/null +++ b/lib/Utils/currencyUtils.dart @@ -0,0 +1,6 @@ +extension CurrencyExtension on String { + + String getCurrencyCode(){ + return substring(0,3); + } +} \ No newline at end of file diff --git a/lib/data/model/Currency.dart b/lib/data/model/Currency.dart new file mode 100644 index 0000000..91b1779 --- /dev/null +++ b/lib/data/model/Currency.dart @@ -0,0 +1,11 @@ +class Currency { + String? from; + String? to; + double? rate; + + Currency(this.from, this.to, this.rate); +} + +abstract class Mapper { + Currency convert(); +} \ No newline at end of file diff --git a/lib/data/network/backupCurrencyApi.dart b/lib/data/network/backupCurrencyApi.dart new file mode 100644 index 0000000..a2dceba --- /dev/null +++ b/lib/data/network/backupCurrencyApi.dart @@ -0,0 +1,35 @@ +import 'package:dio/dio.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:retrofit/retrofit.dart'; + +import '../model/Currency.dart'; + +part 'backupCurrencyApi.g.dart'; + +@RestApi(baseUrl: "https://api.frankfurter.app/") +abstract class BackupCurrencyApi { + factory BackupCurrencyApi(Dio dio, {String baseUrl}) = _BackupCurrencyApi; + + @GET("latest?") + Future> getCurrencyRate(@Query("from") String currencyFrom, + @Query("to") String currencyTo); +} + +@JsonSerializable() +class CurrencyResponse implements Mapper{ + String? data; + double amount; + Map? rates; + String? base; + + CurrencyResponse(this.data, this.amount, this.rates, this.base); + + factory CurrencyResponse.fromJson(Map json) => _$CurrencyResponseFromJson(json); + Map toJson() => _$CurrencyResponseToJson(this); + + @override + Currency convert() { + MapEntry? entry = rates?.entries.elementAt(0); + return Currency(base, entry?.key, entry?.value); + } +} \ No newline at end of file diff --git a/lib/data/network/currencyApi.dart b/lib/data/network/currencyApi.dart new file mode 100644 index 0000000..907e2b2 --- /dev/null +++ b/lib/data/network/currencyApi.dart @@ -0,0 +1,54 @@ +import 'package:dio/dio.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:retrofit/retrofit.dart'; + +import '../model/Currency.dart'; + +part 'currencyApi.g.dart'; + +@RestApi(baseUrl: "https://free.currencyconverterapi.com/api/v3/") +abstract class CurrencyApi { + factory CurrencyApi(Dio dio, {String baseUrl}) = _CurrencyApi; + + @GET("/convert?") + Future> getConversion(@Query("apiKey") String apiKey, @Query("q") String currency); +} + +@JsonSerializable() +class ResponseObject implements Mapper{ + dynamic query; + Map? results; + + ResponseObject({ + this.query, + this.results + }); + + factory ResponseObject.fromJson(Map json) => _$ResponseObjectFromJson(json); + Map toJson() => _$ResponseObjectToJson(this); + + @override + Currency convert() { + CurrencyObject? cur = results?.entries.elementAt(0).value; + return Currency(cur?.fr, cur?.to, cur?.val); + } + +} + +@JsonSerializable() +class CurrencyObject{ + String? id; + String? fr; + String? to; + double? val; + + CurrencyObject({ + this.id, + this.fr, + this.to, + this.val + }); + + factory CurrencyObject.fromJson(Map json) => _$CurrencyObjectFromJson(json); + Map toJson() => _$CurrencyObjectToJson(this); +} \ No newline at end of file diff --git a/lib/data/network/safeApiCall.dart b/lib/data/network/safeApiCall.dart new file mode 100644 index 0000000..08f0373 --- /dev/null +++ b/lib/data/network/safeApiCall.dart @@ -0,0 +1,30 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:retrofit/retrofit.dart'; + +import '../../main.dart'; + +mixin SafeApiCall { + Future getDataFromApiCall(Future> apiCall) async { + try { + HttpResponse httpResponse = await apiCall; + return httpResponse.data; + } on DioError catch(dioError) { + Map? errorResponse = dioError.response?.data; + String error; + + if (errorResponse?["error"] != null){ + error = errorResponse!["error"]; + } else if (dioError.error != null){ + error = dioError.error; + } else { + error = "Failed to retrieve data from api"; + } + + logger.e(dioError.error); + + throw HttpException(error); + } + } +} \ No newline at end of file diff --git a/lib/data/prefs/PreferenceProvider.dart b/lib/data/prefs/PreferenceProvider.dart index f1f5551..5944d16 100644 --- a/lib/data/prefs/PreferenceProvider.dart +++ b/lib/data/prefs/PreferenceProvider.dart @@ -1,5 +1,3 @@ -import 'dart:ffi'; - import 'package:shared_preferences/shared_preferences.dart'; import 'CurrencyPair.dart'; diff --git a/lib/data/repository/Repository.dart b/lib/data/repository/Repository.dart index 68b3776..b317c22 100644 --- a/lib/data/repository/Repository.dart +++ b/lib/data/repository/Repository.dart @@ -1,6 +1,8 @@ +import '../model/Currency.dart'; import '../prefs/CurrencyPair.dart'; abstract class Repository { CurrencyPair getConversionPair(); Future setConversionPair(String fromCurrency, String toCurrency); + Future getConversationRateFromApi(String fromCurrency, String toCurrency); } \ No newline at end of file diff --git a/lib/data/repository/RepositoryImpl.dart b/lib/data/repository/RepositoryImpl.dart index 54abd1d..d085a00 100644 --- a/lib/data/repository/RepositoryImpl.dart +++ b/lib/data/repository/RepositoryImpl.dart @@ -1,11 +1,22 @@ +import 'dart:io'; + +import 'package:easy_cc_flutter/Utils/currencyUtils.dart'; +import 'package:easy_cc_flutter/data/model/Currency.dart'; import 'package:easy_cc_flutter/data/prefs/CurrencyPair.dart'; import 'package:easy_cc_flutter/data/prefs/PreferenceProvider.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import '../../locator.dart'; +import '../../main.dart'; +import '../network/backupCurrencyApi.dart'; +import '../network/currencyApi.dart'; +import '../network/safeApiCall.dart'; import 'Repository.dart'; -class RepositoryImpl extends Repository { +class RepositoryImpl extends Repository with SafeApiCall { final PreferenceProvider _prefs = locator(); + final CurrencyApi _api = locator(); + final BackupCurrencyApi _backupApi = locator(); @override CurrencyPair getConversionPair() { @@ -17,4 +28,20 @@ class RepositoryImpl extends Repository { return _prefs.saveConversionPair(fromCurrency, toCurrency); } + @override + Future getConversationRateFromApi(String fromCurrency, String toCurrency) async { + String from = fromCurrency.getCurrencyCode(); + String to = toCurrency.getCurrencyCode(); + + String currency = "${from}_$to"; + + try { + ResponseObject responseObject = await getDataFromApiCall(_api.getConversion(dotenv.env['apiKey']!, currency)); + return responseObject.convert(); + } on HttpException catch(error) { + logger.e(error); + CurrencyResponse responseObject = await getDataFromApiCall(_backupApi.getCurrencyRate(from, to)); + return responseObject.convert(); + } + } } \ No newline at end of file diff --git a/lib/locator.dart b/lib/locator.dart index 3a2de65..ca4ccfa 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,4 +1,7 @@ +import 'package:dio/dio.dart'; import 'package:easy_cc_flutter/MainViewModel.dart'; +import 'package:easy_cc_flutter/data/network/backupCurrencyApi.dart'; +import 'package:easy_cc_flutter/data/network/currencyApi.dart'; import 'package:easy_cc_flutter/data/repository/RepositoryImpl.dart'; import 'package:get_it/get_it.dart'; @@ -7,8 +10,11 @@ import 'data/prefs/PreferenceProvider.dart'; GetIt locator = GetIt.instance; void setupLocator() { - + final dio = Dio(); locator.registerLazySingleton(() => PreferenceProvider()); + locator.registerLazySingleton(() => CurrencyApi(dio)); + locator.registerLazySingleton(() => BackupCurrencyApi(dio)); locator.registerLazySingleton(() => RepositoryImpl()); locator.registerFactory(() => MainViewModel()); + } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 0b96420..b159706 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:logger/logger.dart'; import 'Home.dart'; import 'data/prefs/PreferenceProvider.dart'; import 'locator.dart'; +var logger = Logger( + printer: PrettyPrinter(), +); + void main() async { WidgetsFlutterBinding.ensureInitialized(); setupLocator(); + await dotenv.load(); await locator().init(); runApp(const MyApp()); } diff --git a/pubspec.lock b/pubspec.lock index 0df5222..110524a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,27 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "47.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "4.7.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" async: dependency: transitive description: @@ -15,6 +36,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.10" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.4" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.4.1" characters: dependency: transitive description: @@ -22,6 +99,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" clock: dependency: transitive description: @@ -29,6 +113,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.3.0" collection: dependency: transitive description: @@ -36,6 +127,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" crypto: dependency: transitive description: @@ -50,6 +148,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.4" + dio: + dependency: transitive + description: + name: dio + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.6" dropdown_search: dependency: "direct main" description: @@ -85,11 +197,25 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.4" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.2" flutter_lints: dependency: "direct dev" description: @@ -107,6 +233,13 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" get: dependency: transitive description: @@ -121,6 +254,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "7.2.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" js: dependency: transitive description: @@ -128,6 +296,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "6.3.2" lazy_evaluation: dependency: "direct main" description: @@ -142,6 +324,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.0" + logger: + dependency: "direct main" + description: + name: logger + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" matcher: dependency: transitive description: @@ -163,6 +359,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" nested: dependency: transitive description: @@ -170,6 +373,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" path: dependency: transitive description: @@ -212,6 +422,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.1" process: dependency: transitive description: @@ -226,6 +443,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.0.3" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + retrofit: + dependency: "direct main" + description: + name: retrofit + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1+1" + retrofit_generator: + dependency: "direct dev" + description: + name: retrofit_generator + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.3+2" sealed_annotations: dependency: "direct main" description: @@ -289,11 +541,39 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.3" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.3" source_span: dependency: transitive description: @@ -336,6 +616,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -357,6 +644,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.13" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" toast: dependency: "direct main" description: @@ -364,6 +658,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.3.0" + tuple: + dependency: transitive + description: + name: tuple + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" typed_data: dependency: transitive description: @@ -392,6 +693,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.3" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" win32: dependency: transitive description: @@ -406,6 +721,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.0+2" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" sdks: dart: ">=2.18.0-190.0.dev <3.0.0" flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index d98e6aa..b37e696 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,11 +44,17 @@ dependencies: cupertino_icons: ^1.0.2 shared_preferences: ^2.0.15 get_it: ^7.2.0 + retrofit: ^3.0.1+1 + logger: ^1.1.0 + flutter_dotenv: ^5.0.2 dev_dependencies: flutter_test: sdk: flutter + retrofit_generator: '>=4.0.0 <5.0.0' + build_runner: '>=2.2.1 <4.0.0' + json_serializable: '>4.4.0' # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your @@ -68,7 +74,8 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: + assets: + - .env # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg