From 75bdcde364502d88f06903269b824a975212a156 Mon Sep 17 00:00:00 2001 From: hmalik144 Date: Sun, 30 Oct 2022 14:10:16 +0000 Subject: [PATCH] - Homescreen widget for android added --- android/app/build.gradle | 2 +- .../h_mal/easycc/AppWidgetProvider.kt | 53 ++++++++++++++-- .../CurrencyAppWidgetConfigureActivity.kt | 51 +++++++++------- .../appttude/h_mal/easycc/WidgetViewModel.kt | 57 ------------------ .../res/drawable/easyycc_widget_preview.png | Bin 0 -> 19203 bytes .../main/res/xml/currency_app_widget_info.xml | 11 ++++ lib/Utils/currency_utils.dart | 3 + lib/base_widget.dart | 2 +- lib/data/network/app_dio.dart | 4 +- lib/data/repository/repository_impl.dart | 9 +-- lib/home.dart | 9 +-- lib/locator.dart | 8 +-- lib/main.dart | 56 ++++++++++++----- lib/main_view_model.dart | 8 +-- test/unit_test/repository_test.dart | 18 +++--- test/unit_test/viewmodel_test.dart | 9 +-- 16 files changed, 166 insertions(+), 134 deletions(-) delete mode 100644 android/app/src/main/kotlin/com/appttude/h_mal/easycc/WidgetViewModel.kt create mode 100644 android/app/src/main/res/drawable/easyycc_widget_preview.png create mode 100644 android/app/src/main/res/xml/currency_app_widget_info.xml diff --git a/android/app/build.gradle b/android/app/build.gradle index c44b2e2..662ef74 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -47,7 +47,7 @@ android { applicationId "com.appttude.h_mal.easycc" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. - minSdkVersion flutter.minSdkVersion + minSdkVersion localProperties.getProperty('flutter.minSdkVersion').toInteger() targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/src/main/kotlin/com/appttude/h_mal/easycc/AppWidgetProvider.kt b/android/app/src/main/kotlin/com/appttude/h_mal/easycc/AppWidgetProvider.kt index 093f328..20f59c8 100644 --- a/android/app/src/main/kotlin/com/appttude/h_mal/easycc/AppWidgetProvider.kt +++ b/android/app/src/main/kotlin/com/appttude/h_mal/easycc/AppWidgetProvider.kt @@ -1,14 +1,19 @@ package com.appttude.h_mal.easycc import android.appwidget.AppWidgetManager +import android.content.ComponentName import android.content.Context +import android.content.Intent import android.content.SharedPreferences import android.net.Uri import android.widget.RemoteViews +import android.widget.Toast import es.antonborri.home_widget.HomeWidgetBackgroundIntent import es.antonborri.home_widget.HomeWidgetLaunchIntent +import es.antonborri.home_widget.HomeWidgetPlugin import es.antonborri.home_widget.HomeWidgetProvider + class AppWidgetProvider : HomeWidgetProvider(){ override fun onUpdate( context: Context, @@ -19,16 +24,22 @@ class AppWidgetProvider : HomeWidgetProvider(){ appWidgetIds.forEach { widgetId -> val views = RemoteViews(context.packageName, R.layout.currency_app_widget).apply { // Data from background operation received - val from: String? = widgetData.getString("from", null) - val to: String? = widgetData.getString("to", null) - val rate: String? = widgetData.getString("rate", null) + val from: String? = widgetData.getString("${widgetId}_from", null) + val to: String? = widgetData.getString("${widgetId}_to", null) + val rate: String? = widgetData.getString("${widgetId}_rate", null) + + if (from.isNullOrBlank() or to.isNullOrBlank() or rate.isNullOrBlank()) { + Toast.makeText(context, "Unable to review data for widget", Toast.LENGTH_SHORT).show() + return@apply + } val titleString = "${from}${to}" setTextViewText(R.id.exchangeName, titleString) setTextViewText(R.id.exchangeRate, rate.toString()) - val uri = Uri.parse("myAppWidget://update") - uri.buildUpon().query(widgetId.toString()).build() + val uri = Uri.parse("myAppWidget://updatewidget").buildUpon() + .appendQueryParameter("id", widgetId.toString()) + .build() setImageViewResource(R.id.refresh_icon, R.drawable.ic_refresh_white_24dp) val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(context, uri) @@ -42,4 +53,36 @@ class AppWidgetProvider : HomeWidgetProvider(){ appWidgetManager.updateAppWidget(widgetId, views) } } + + override fun onReceive(context: Context?, intent: Intent?) { + super.onReceive(context, intent) + + when (intent?.action) { + + } + val appWidgetManager = AppWidgetManager.getInstance(context); + val appWidgetIds = appWidgetManager.getAppWidgetIds( + context?.let { ComponentName(it, this::class.java) }) + val widgetDate = context?.let { HomeWidgetPlugin.getData(it) } + + appWidgetIds.forEach { widgetId -> + + + } + } + + override fun onDeleted(context: Context?, appWidgetIds: IntArray?) { + super.onDeleted(context, appWidgetIds) + + appWidgetIds?.forEach { widgetId -> + val uri = Uri.parse("myAppWidget://deletewidget") + uri.buildUpon().appendQueryParameter("id", widgetId.toString()).build() + + context?.let { + HomeWidgetBackgroundIntent + .getBroadcast(it, uri) + .send() + } + } + } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/appttude/h_mal/easycc/CurrencyAppWidgetConfigureActivity.kt b/android/app/src/main/kotlin/com/appttude/h_mal/easycc/CurrencyAppWidgetConfigureActivity.kt index 3ed4817..edf8223 100644 --- a/android/app/src/main/kotlin/com/appttude/h_mal/easycc/CurrencyAppWidgetConfigureActivity.kt +++ b/android/app/src/main/kotlin/com/appttude/h_mal/easycc/CurrencyAppWidgetConfigureActivity.kt @@ -1,24 +1,13 @@ package com.appttude.h_mal.easycc import android.app.Activity -import android.app.PendingIntent import android.appwidget.AppWidgetManager -import android.content.Intent import android.net.Uri -import android.os.Build import android.os.Bundle import android.view.View import android.widget.TextView -import androidx.activity.viewModels -import com.appttude.h_mal.easycc.databinding.CurrencyAppWidgetConfigureBinding -import com.appttude.h_mal.easycc.ui.BaseActivity -import com.appttude.h_mal.easycc.ui.main.CustomDialogClass -import com.appttude.h_mal.easycc.utils.transformIntToArray -import com.appttude.h_mal.easycc.widget.CurrencyAppWidgetKotlin -import dagger.hilt.android.AndroidEntryPoint +import android.widget.Toast import es.antonborri.home_widget.HomeWidgetBackgroundIntent -import es.antonborri.home_widget.HomeWidgetBackgroundReceiver -import es.antonborri.home_widget.HomeWidgetPlugin /** * The configuration screen for the [CurrencyAppWidgetKotlin] AppWidget. @@ -28,6 +17,9 @@ class CurrencyAppWidgetConfigureActivity : Activity(), private var mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + private var top: String? = null + private var bottom: String? = null + public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.currency_app_widget_configure) @@ -61,18 +53,23 @@ class CurrencyAppWidgetConfigureActivity : Activity(), override fun onClick(view: View?) { when (view?.tag.toString()) { "top", "bottom" -> showCustomDialog(view) - "submit" -> viewModel.submitSelectionOnClick() - else -> { - return - } + "submit" -> displaySubmitDialog() } } private fun displaySubmitDialog() { - val message = viewModel.getSubmitDialogMessage() - WidgetSubmitDialog(this, message, object : DialogSubmit { + if (top == null || bottom == null) { + Toast.makeText(this, "Selections incomplete", Toast.LENGTH_SHORT).show() + return + } + if (top == bottom) { + Toast.makeText(this, "Selected rates cannot be the same", Toast.LENGTH_SHORT).show() + return + } + + WidgetSubmitDialog(this, getSubmitDialogMessage(), object : DialogSubmit { override fun onSubmit() { - sendUpdateIntent() + sendUpdateIntent(top!!, bottom!!) finishCurrencyWidgetActivity() } }).show() @@ -82,7 +79,10 @@ class CurrencyAppWidgetConfigureActivity : Activity(), private fun showCustomDialog(view: View?) { CustomDialogClass(this) { (view as TextView).text = it - viewModel.setCurrencyName(view.tag, it) + when (view.tag.toString()) { + "top" -> top = it + "bottom" -> bottom = it + } }.show() } @@ -97,7 +97,7 @@ class CurrencyAppWidgetConfigureActivity : Activity(), fun sendUpdateIntent(from: String, to: String) { // It is the responsibility of the configuration activity to update the app widget // Send update broadcast to widget app class - val uri = Uri.parse("myAppWidget://createWidget").buildUpon() + val uri = Uri.parse("myAppWidget://createwidget").buildUpon() .appendQueryParameter("id", mAppWidgetId.toString()) .appendQueryParameter("from", from) .appendQueryParameter("to", to) @@ -107,4 +107,13 @@ class CurrencyAppWidgetConfigureActivity : Activity(), backgroundIntent.send() } + private fun getSubmitDialogMessage(): String { + val widgetName = getWidgetStringName() + return StringBuilder().append("Create widget for ") + .append(widgetName) + .append("?").toString() + } + + private fun getWidgetStringName() = "${top!!.substring(0, 3)}${bottom!!.substring(0, 3)}" + } diff --git a/android/app/src/main/kotlin/com/appttude/h_mal/easycc/WidgetViewModel.kt b/android/app/src/main/kotlin/com/appttude/h_mal/easycc/WidgetViewModel.kt deleted file mode 100644 index 068eee4..0000000 --- a/android/app/src/main/kotlin/com/appttude/h_mal/easycc/WidgetViewModel.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.appttude.h_mal.easycc - -import androidx.lifecycle.ViewModel -import com.appttude.h_mal.easycc.data.repository.Repository -import com.appttude.h_mal.easycc.ui.BaseViewModel -import com.appttude.h_mal.easycc.utils.trimToThree -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -class WidgetViewModel: ViewModel() { - - var appWidgetId: Int? = null - - var rateIdFrom: String? = null - var rateIdTo: String? = null - - // Setup viewmodel app widget ID - // Set default values for text views - fun initiate(appId: Int) { - appWidgetId = appId - } - - // Retrieve name for submit dialog (eg. AUDGBP) - fun getSubmitDialogMessage(): String { - val widgetName = getWidgetStringName() - return StringBuilder().append("Create widget for ") - .append(widgetName) - .append("?").toString() - } - - fun submitSelectionOnClick() { - if (rateIdTo == null || rateIdFrom == null) { - onError("Selections incomplete") - return - } - if (rateIdFrom == rateIdTo) { - onError("Selected rates cannot be the same") - return - } - onSuccess(Unit) - } - - fun setWidgetStored() { - - } - - // Start operation based on dialog selection - fun setCurrencyName(tag: Any?, currencyName: String) { - when (tag.toString()) { - "top" -> rateIdFrom = currencyName - "bottom" -> rateIdTo = currencyName - } - } - - private fun getWidgetStringName() = "${rateIdFrom!!.substring(0, 3)}${rateIdTo!!.substring(0, 3)}" - -} \ No newline at end of file diff --git a/android/app/src/main/res/drawable/easyycc_widget_preview.png b/android/app/src/main/res/drawable/easyycc_widget_preview.png new file mode 100644 index 0000000000000000000000000000000000000000..144292ebdf863994e77f4e725100fe6f48ef4c7b GIT binary patch literal 19203 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 + \ No newline at end of file diff --git a/lib/Utils/currency_utils.dart b/lib/Utils/currency_utils.dart index fb739a6..3169ac9 100644 --- a/lib/Utils/currency_utils.dart +++ b/lib/Utils/currency_utils.dart @@ -2,6 +2,9 @@ extension CurrencyExtension on String { /// Convert currency string into currency code /// eg. "AUD - Australian Dollar" to "AUD" String getCurrencyCode(){ + if (length == 3) { + return this; + } return substring(0,3); } } \ No newline at end of file diff --git a/lib/base_widget.dart b/lib/base_widget.dart index 1bd296e..11ab430 100644 --- a/lib/base_widget.dart +++ b/lib/base_widget.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; import 'package:toast/toast.dart'; -import 'base_viewmodel.dart'; import 'Utils/constants.dart'; import 'Utils/view_state.dart'; import 'Utils/view_utils.dart'; +import 'base_viewmodel.dart'; abstract class BaseStatelessWidget extends StatelessWidget { diff --git a/lib/data/network/app_dio.dart b/lib/data/network/app_dio.dart index 3b4c6df..7414e6a 100644 --- a/lib/data/network/app_dio.dart +++ b/lib/data/network/app_dio.dart @@ -5,8 +5,8 @@ class AppDio { static Dio createDio() { Dio dio = Dio( BaseOptions( - receiveTimeout: 60000, - connectTimeout: 120000, + receiveTimeout: 30000, + connectTimeout: 30000, ) ); dio.interceptors.add(LogInterceptor()); diff --git a/lib/data/repository/repository_impl.dart b/lib/data/repository/repository_impl.dart index 54ce8b8..5d6f3ba 100644 --- a/lib/data/repository/repository_impl.dart +++ b/lib/data/repository/repository_impl.dart @@ -4,7 +4,6 @@ import 'package:easy_cc_flutter/Utils/currency_utils.dart'; import 'package:easy_cc_flutter/data/model/currency.dart'; import 'package:easy_cc_flutter/data/prefs/currency_pair.dart'; -import '../../locator.dart'; import '../../main.dart'; import '../network/backup_currency_api.dart'; import '../network/currency_api.dart'; @@ -13,9 +12,11 @@ import '../prefs/preference_provider.dart'; import 'repository.dart'; class RepositoryImpl extends Repository with SafeApiCall { - final PreferenceProvider _prefs = locator(); - final CurrencyApi _api = locator(); - final BackupCurrencyApi _backupApi = locator(); + final PreferenceProvider _prefs; + final CurrencyApi _api; + final BackupCurrencyApi _backupApi; + + RepositoryImpl(this._prefs, this._api, this._backupApi); @override CurrencyPair getConversionPair() { diff --git a/lib/home.dart b/lib/home.dart index a2fac5a..dc891cb 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -1,19 +1,20 @@ -import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:easy_cc_flutter/Utils/selection_type.dart'; -import 'package:easy_cc_flutter/views/drop_down_box.dart'; +import 'package:easy_cc_flutter/locator.dart'; +import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:easy_cc_flutter/views/converter_edit_text.dart'; +import 'package:easy_cc_flutter/views/drop_down_box.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'base_widget.dart'; import 'Utils/constants.dart'; +import 'base_widget.dart'; class HomePage extends BaseStatelessWidget { const HomePage({super.key}); @override MainViewModel createViewModel() { - return MainViewModel(); + return locator(); } @override diff --git a/lib/locator.dart b/lib/locator.dart index edb970c..8ba82fb 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,10 +1,10 @@ -import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:easy_cc_flutter/data/network/backup_currency_api.dart'; import 'package:easy_cc_flutter/data/network/currency_api.dart'; import 'package:easy_cc_flutter/data/repository/repository_impl.dart'; +import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:get_it/get_it.dart'; - import 'data/prefs/preference_provider.dart'; +import 'data/repository/repository.dart'; GetIt locator = GetIt.instance; @@ -12,6 +12,6 @@ void setupLocator() { locator.registerLazySingleton(() => PreferenceProvider()); locator.registerLazySingleton(() => CurrencyApi.create()); locator.registerLazySingleton(() => BackupCurrencyApi.create()); - locator.registerLazySingleton(() => RepositoryImpl()); - locator.registerFactory(() => MainViewModel()); + locator.registerLazySingleton(() => RepositoryImpl(locator(), locator(),locator())); + locator.registerFactory(() => MainViewModel(locator())); } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 15af659..06bf8d6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,14 @@ +import 'package:easy_cc_flutter/Utils/currency_utils.dart'; +import 'package:easy_cc_flutter/data/network/backup_currency_api.dart'; +import 'package:easy_cc_flutter/data/network/currency_api.dart'; import 'package:flutter/material.dart'; import 'package:home_widget/home_widget.dart'; import 'package:logger/logger.dart'; +import 'data/model/currency.dart'; import 'data/prefs/preference_provider.dart'; +import 'data/repository/repository.dart'; +import 'data/repository/repository_impl.dart'; import 'home.dart'; import 'locator.dart'; @@ -10,34 +16,56 @@ var logger = Logger( printer: PrettyPrinter(), ); -void main() async { +Future main() async { WidgetsFlutterBinding.ensureInitialized(); setupLocator(); await locator().init(); + await HomeWidget.registerBackgroundCallback(backgroundCallback); runApp(const MyApp()); } Future backgroundCallback(Uri? uri) async { - if (uri?.host == 'updatecounter') { + PreferenceProvider prefs = PreferenceProvider(); + await prefs.init(); + CurrencyApi api = CurrencyApi.create(); + BackupCurrencyApi backupApi = BackupCurrencyApi.create(); + RepositoryImpl repository = RepositoryImpl(prefs, api, backupApi); + + if (uri?.host == 'updatewidget') { Map? querys = uri?.queryParameters; + String? widgetId = querys?["id"]; - int _counter = 0; - await HomeWidget.getWidgetData('_counter', defaultValue: 0).then((int? value) { - _counter = value ?? 0; - _counter++; - }); - await HomeWidget.saveWidgetData('_counter', _counter); - await HomeWidget.updateWidget(name: 'AppWidgetProvider', iOSName: 'AppWidgetProvider'); - } else if (uri?.host == 'createWidget') { + await updateWidget(widgetId, repository); + } else if (uri?.host == 'createwidget') { Map? querys = uri?.queryParameters; - String? id = querys?["id"]; - String? from = querys?["from"]; - String? to = querys?["to"]; + String? widgetId = querys?["id"]; + String? from = querys?["from"]?.getCurrencyCode(); + String? to = querys?["to"]?.getCurrencyCode(); + await HomeWidget.saveWidgetData("${widgetId}_from", from); + await HomeWidget.saveWidgetData("${widgetId}_to", to); + await updateWidget(widgetId, repository); } } +Future updateWidget(String? widgetId, Repository repository) async { + String? from = await HomeWidget.getWidgetData("${widgetId}_from"); + String? to = await HomeWidget.getWidgetData("${widgetId}_to"); + + if (from == null || to == null) { + return; + } + + Currency currency = await repository.getConversationRateFromApi(from, to); + + await HomeWidget.saveWidgetData("${widgetId}_from", from); + await HomeWidget.saveWidgetData("${widgetId}_to", to); + await HomeWidget.saveWidgetData("${widgetId}_rate", currency.rate.toString()); + + await HomeWidget.updateWidget(name: 'AppWidgetProvider', iOSName: 'AppWidgetProvider'); +} + class MyApp extends StatelessWidget { const MyApp({super.key}); @@ -58,7 +86,7 @@ class MyApp extends StatelessWidget { // is not restarted. primarySwatch: Colors.blue, ), - home: const HomePage(), + home: HomePage(), ); } } diff --git a/lib/main_view_model.dart b/lib/main_view_model.dart index 7dfb31b..98e522f 100644 --- a/lib/main_view_model.dart +++ b/lib/main_view_model.dart @@ -1,14 +1,14 @@ -import 'package:easy_cc_flutter/base_viewmodel.dart'; import 'package:easy_cc_flutter/Utils/selection_type.dart'; +import 'package:easy_cc_flutter/base_viewmodel.dart'; import 'Utils/constants.dart'; import 'data/prefs/currency_pair.dart'; import 'data/repository/repository.dart'; -import 'data/repository/repository_impl.dart'; -import 'locator.dart'; class MainViewModel extends BaseViewmodel { - final Repository _repository = locator(); + final Repository _repository; + + MainViewModel(this._repository); double conversionRate = 1.0; diff --git a/test/unit_test/repository_test.dart b/test/unit_test/repository_test.dart index db8d905..cc3c59a 100644 --- a/test/unit_test/repository_test.dart +++ b/test/unit_test/repository_test.dart @@ -8,7 +8,6 @@ import 'package:easy_cc_flutter/data/network/currency_api.dart'; import 'package:easy_cc_flutter/data/prefs/currency_pair.dart'; import 'package:easy_cc_flutter/data/prefs/preference_provider.dart'; import 'package:easy_cc_flutter/data/repository/repository_impl.dart'; -import 'package:easy_cc_flutter/locator.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; @@ -29,7 +28,8 @@ import 'repository_test.mocks.dart'; MockSpec(onMissingStub: OnMissingStub.returnDefault) ]) void main() { - late RepositoryImpl repository; + late RepositoryImpl sut; + late PreferenceProvider preferenceProvider; late CurrencyApi currencyApi; late BackupCurrencyApi backupCurrencyApi; @@ -44,11 +44,7 @@ void main() { currencyApi = MockCurrencyApi(); backupCurrencyApi = MockBackupCurrencyApi(); - locator.registerLazySingleton(() => preferenceProvider); - locator.registerLazySingleton(() => currencyApi); - locator.registerLazySingleton(() => backupCurrencyApi); - - repository = RepositoryImpl(); + sut = RepositoryImpl(preferenceProvider, currencyApi, backupCurrencyApi); }); test('get currency pair from prefs', () { @@ -59,7 +55,7 @@ void main() { when(preferenceProvider.getConversionPair()).thenReturn(pair); // Then - expect(repository.getConversionPair(), pair); + expect(sut.getConversionPair(), pair); }); test('get currency rate from API', () async { @@ -77,7 +73,7 @@ void main() { // Then Currency retrieved = - await repository.getConversationRateFromApi(fromCurrency, toCurrency); + await sut.getConversationRateFromApi(fromCurrency, toCurrency); expect(retrieved.toString(), currencyObject.toString()); }); @@ -98,7 +94,7 @@ void main() { // Then Currency retrieved = - await repository.getConversationRateFromApi(fromCurrency, toCurrency); + await sut.getConversationRateFromApi(fromCurrency, toCurrency); expect(retrieved.toString(), currencyObject.toString()); }); @@ -115,7 +111,7 @@ void main() { .thenAnswer((_) async => Future.error(backUpError)); // Then - expect(() async => await repository.getConversationRateFromApi(fromCurrency, toCurrency), + expect(() async => await sut.getConversationRateFromApi(fromCurrency, toCurrency), throwsA(predicate((e) => e is HttpException && e.message == 'Error message'))); diff --git a/test/unit_test/viewmodel_test.dart b/test/unit_test/viewmodel_test.dart index 738f1af..9e11ef7 100644 --- a/test/unit_test/viewmodel_test.dart +++ b/test/unit_test/viewmodel_test.dart @@ -1,15 +1,14 @@ import 'dart:io'; -import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:easy_cc_flutter/Utils/selection_type.dart'; +import 'package:easy_cc_flutter/Utils/view_state.dart'; import 'package:easy_cc_flutter/data/model/currency.dart'; import 'package:easy_cc_flutter/data/prefs/currency_pair.dart'; import 'package:easy_cc_flutter/data/repository/repository_impl.dart'; -import 'package:easy_cc_flutter/locator.dart'; +import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; -import 'package:easy_cc_flutter/Utils/view_state.dart'; import 'viewmodel_test.mocks.dart'; @@ -29,9 +28,7 @@ void main() { // Create mock object. repository = MockRepositoryImpl(); - locator.registerLazySingleton(() => repository); - - mainViewModel = MainViewModel(); + mainViewModel = MainViewModel(repository); }); test('get currency pair from prefs', () {