From 2e59ea07f97f86f5bb9472668a5de3f2207a68e4 Mon Sep 17 00:00:00 2001 From: hmalik144 Date: Sun, 17 May 2020 14:15:23 +0100 Subject: [PATCH] Widget Viewmodel updated to use live data Widget activity, dialog and viewmodel cleaned up folder structure changed removal of legacy java code --- .../h_mal/easycc/MainActivityTest.java | 2 - app/src/main/AndroidManifest.xml | 8 +- .../easycc/{mvvm => }/application/AppClass.kt | 18 +- .../{mvvm => }/data/network/SafeApiRequest.kt | 2 +- .../data/network/api/CurrencyApi.kt | 22 +- .../NetworkConnectionInterceptor.kt | 2 +- .../network/interceptors/QueryInterceptor.kt | 5 +- .../data/network/response/ResponseObject.kt | 4 +- .../data/prefs/PreferenceProvider.kt | 2 +- .../{mvvm => }/data/repository/Repository.kt | 4 +- .../data/repository/RepositoryImpl.kt | 12 +- .../easycc/legacy/CurrencyAppWidget.java | 161 -------- .../CurrencyAppWidgetConfigureActivity.java | 227 ----------- .../h_mal/easycc/legacy/MainActivityJava.java | 378 ------------------ .../h_mal/easycc/legacy/PublicMethods.java | 108 ----- .../{mvvm => }/models/CurrencyObject.kt | 2 +- .../h_mal/easycc/mvvm/ui/app/RateListener.kt | 7 - ...urrencyAppWidgetConfigureActivityKotlin.kt | 70 ---- .../mvvm/ui/widget/WidgetSubmitDialog.kt | 59 --- .../easycc/mvvm/ui/widget/WidgetViewModel.kt | 83 ---- .../h_mal/easycc/mvvm/utils/PrimitiveUtils.kt | 22 - .../ui/app => ui/main}/CustomDialogClass.kt | 11 +- .../{mvvm/ui/app => ui/main}/MainActivity.kt | 41 +- .../{mvvm/ui/app => ui/main}/MainViewModel.kt | 53 ++- .../app => ui/main}/MainViewModelFactory.kt | 8 +- ...urrencyAppWidgetConfigureActivityKotlin.kt | 151 +++++++ .../ui/widget/WidgetItemSelectDialog.kt | 4 +- .../easycc/ui/widget/WidgetSubmitDialog.kt | 38 ++ .../h_mal/easycc/ui/widget/WidgetViewModel.kt | 70 ++++ .../ui/widget/WidgetViewModelFactory.kt | 4 +- .../h_mal/easycc/utils/PrimitiveUtils.kt | 36 ++ .../easycc/{mvvm => }/utils/ViewUtils.kt | 4 +- .../ui => }/widget/CurrencyAppWidgetKotlin.kt | 8 +- app/src/main/res/layout/activity_main.xml | 13 +- .../layout/currency_app_widget_configure.xml | 15 +- .../main/res/xml/currency_app_widget_info.xml | 2 +- .../xml/currency_kotlin_app_widget_info.xml | 2 +- .../h_mal/easycc/ExampleUnitTest.java | 2 +- .../repository/RepositoryNetworkTest.kt | 15 +- .../repository/RepositoryStorageTest.kt | 8 +- 40 files changed, 437 insertions(+), 1246 deletions(-) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/application/AppClass.kt (58%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/network/SafeApiRequest.kt (97%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/network/api/CurrencyApi.kt (65%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/network/interceptors/NetworkConnectionInterceptor.kt (95%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/network/interceptors/QueryInterceptor.kt (82%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/network/response/ResponseObject.kt (64%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/prefs/PreferenceProvider.kt (98%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/repository/Repository.kt (80%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/data/repository/RepositoryImpl.kt (79%) delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidget.java delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidgetConfigureActivity.java delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/legacy/MainActivityJava.java delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/legacy/PublicMethods.java rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/models/CurrencyObject.kt (86%) delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/RateListener.kt delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetSubmitDialog.kt delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModel.kt delete mode 100644 app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/PrimitiveUtils.kt rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm/ui/app => ui/main}/CustomDialogClass.kt (80%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm/ui/app => ui/main}/MainActivity.kt (82%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm/ui/app => ui/main}/MainViewModel.kt (64%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm/ui/app => ui/main}/MainViewModelFactory.kt (64%) create mode 100644 app/src/main/java/com/appttude/h_mal/easycc/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/ui/widget/WidgetItemSelectDialog.kt (94%) create mode 100644 app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetSubmitDialog.kt create mode 100644 app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModel.kt rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/ui/widget/WidgetViewModelFactory.kt (74%) create mode 100644 app/src/main/java/com/appttude/h_mal/easycc/utils/PrimitiveUtils.kt rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm => }/utils/ViewUtils.kt (78%) rename app/src/main/java/com/appttude/h_mal/easycc/{mvvm/ui => }/widget/CurrencyAppWidgetKotlin.kt (95%) diff --git a/app/src/androidTest/java/com/appttude/h_mal/easycc/MainActivityTest.java b/app/src/androidTest/java/com/appttude/h_mal/easycc/MainActivityTest.java index 7879b64..dff6430 100644 --- a/app/src/androidTest/java/com/appttude/h_mal/easycc/MainActivityTest.java +++ b/app/src/androidTest/java/com/appttude/h_mal/easycc/MainActivityTest.java @@ -1,8 +1,6 @@ package com.appttude.h_mal.easycc; -import org.junit.Before; - public class MainActivityTest { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6d243cc..9f1b6f9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,14 +13,14 @@ android:anyDensity="true" /> - + @@ -30,12 +30,12 @@ android:resource="@xml/currency_app_widget_info" /> - + - + diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/application/AppClass.kt b/app/src/main/java/com/appttude/h_mal/easycc/application/AppClass.kt similarity index 58% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/application/AppClass.kt rename to app/src/main/java/com/appttude/h_mal/easycc/application/AppClass.kt index c68e112..a3f6e0c 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/application/AppClass.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/application/AppClass.kt @@ -1,13 +1,13 @@ -package com.appttude.h_mal.easycc.mvvm.application +package com.appttude.h_mal.easycc.application import android.app.Application -import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl -import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.NetworkConnectionInterceptor -import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.QueryInterceptor -import com.appttude.h_mal.easycc.mvvm.data.network.api.CurrencyApi -import com.appttude.h_mal.easycc.mvvm.data.prefs.PreferenceProvider -import com.appttude.h_mal.easycc.mvvm.ui.app.MainViewModelFactory -import com.appttude.h_mal.easycc.mvvm.ui.widget.WidgetViewModelFactory +import com.appttude.h_mal.easycc.data.network.api.CurrencyApi +import com.appttude.h_mal.easycc.data.network.interceptors.NetworkConnectionInterceptor +import com.appttude.h_mal.easycc.data.network.interceptors.QueryInterceptor +import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider +import com.appttude.h_mal.easycc.data.repository.RepositoryImpl +import com.appttude.h_mal.easycc.ui.main.MainViewModelFactory +import com.appttude.h_mal.easycc.ui.widget.WidgetViewModelFactory import org.kodein.di.Kodein import org.kodein.di.KodeinAware import org.kodein.di.android.x.androidXModule @@ -18,9 +18,11 @@ import org.kodein.di.generic.singleton class AppClass : Application(), KodeinAware { + // Kodein Dependecy Injection created in Application class override val kodein by Kodein.lazy { import(androidXModule(this@AppClass)) + // instance() can be context or other binding created bind() from singleton { NetworkConnectionInterceptor(instance()) } bind() from singleton { QueryInterceptor() } bind() from singleton { CurrencyApi(instance(),instance()) } diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/SafeApiRequest.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/network/SafeApiRequest.kt similarity index 97% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/SafeApiRequest.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/network/SafeApiRequest.kt index fc949eb..f594727 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/SafeApiRequest.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/network/SafeApiRequest.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.data.network +package com.appttude.h_mal.easycc.data.network import android.util.Log import org.json.JSONException diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/api/CurrencyApi.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/network/api/CurrencyApi.kt similarity index 65% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/api/CurrencyApi.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/network/api/CurrencyApi.kt index f21f614..6ead166 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/api/CurrencyApi.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/network/api/CurrencyApi.kt @@ -1,8 +1,8 @@ -package com.appttude.h_mal.easycc.mvvm.data.network.api +package com.appttude.h_mal.easycc.data.network.api -import com.appttude.h_mal.easycc.mvvm.data.network.response.ResponseObject -import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.NetworkConnectionInterceptor -import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.QueryInterceptor +import com.appttude.h_mal.easycc.data.network.interceptors.NetworkConnectionInterceptor +import com.appttude.h_mal.easycc.data.network.interceptors.QueryInterceptor +import com.appttude.h_mal.easycc.data.network.response.ResponseObject import okhttp3.OkHttpClient import retrofit2.Response import retrofit2.Retrofit @@ -10,20 +10,29 @@ import retrofit2.converter.gson.GsonConverterFactory import retrofit2.http.GET import retrofit2.http.Query - +/** + * Retrofit2 Network class to create network requests + */ interface CurrencyApi { + // Get rate from server with arguments passed in Repository + @GET("convert?") + suspend fun getCurrencyRate(@Query("q") currency: String): Response + + // interface invokation to be used in application class companion object{ operator fun invoke( networkConnectionInterceptor: NetworkConnectionInterceptor, queryInterceptor: QueryInterceptor ) : CurrencyApi{ + // okkHttpclient with injected interceptors val okkHttpclient = OkHttpClient.Builder() .addInterceptor(queryInterceptor) .addNetworkInterceptor(networkConnectionInterceptor) .build() + // Build retrofit return Retrofit.Builder() .client(okkHttpclient) .baseUrl("https://free.currencyconverterapi.com/api/v3/") @@ -33,7 +42,6 @@ interface CurrencyApi { } } - @GET("convert?") - suspend fun getCurrencyRate(@Query("q") currency: String): Response + } \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/interceptors/NetworkConnectionInterceptor.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/network/interceptors/NetworkConnectionInterceptor.kt similarity index 95% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/interceptors/NetworkConnectionInterceptor.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/network/interceptors/NetworkConnectionInterceptor.kt index 089d8ec..78a642d 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/interceptors/NetworkConnectionInterceptor.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/network/interceptors/NetworkConnectionInterceptor.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.data.network.interceptors +package com.appttude.h_mal.easycc.data.network.interceptors import android.content.Context import android.net.ConnectivityManager diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/interceptors/QueryInterceptor.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/network/interceptors/QueryInterceptor.kt similarity index 82% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/interceptors/QueryInterceptor.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/network/interceptors/QueryInterceptor.kt index f62be12..9f61b41 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/interceptors/QueryInterceptor.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/network/interceptors/QueryInterceptor.kt @@ -1,8 +1,5 @@ -package com.appttude.h_mal.easycc.mvvm.data.network.interceptors +package com.appttude.h_mal.easycc.data.network.interceptors -import android.content.Context -import android.net.ConnectivityManager -import android.net.NetworkCapabilities import com.appttude.h_mal.easycc.BuildConfig import okhttp3.HttpUrl import okhttp3.Interceptor diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/response/ResponseObject.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/network/response/ResponseObject.kt similarity index 64% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/response/ResponseObject.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/network/response/ResponseObject.kt index 6116763..0d301e5 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/network/response/ResponseObject.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/network/response/ResponseObject.kt @@ -1,6 +1,6 @@ -package com.appttude.h_mal.easycc.mvvm.data.network.response +package com.appttude.h_mal.easycc.data.network.response -import com.appttude.h_mal.easycc.mvvm.models.CurrencyObject +import com.appttude.h_mal.easycc.models.CurrencyObject import com.google.gson.annotations.SerializedName class ResponseObject( diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/prefs/PreferenceProvider.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/prefs/PreferenceProvider.kt similarity index 98% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/prefs/PreferenceProvider.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/prefs/PreferenceProvider.kt index be5b979..f6768f9 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/prefs/PreferenceProvider.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/prefs/PreferenceProvider.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.data.prefs +package com.appttude.h_mal.easycc.data.prefs import android.content.Context import android.content.SharedPreferences diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/repository/Repository.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/repository/Repository.kt similarity index 80% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/repository/Repository.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/repository/Repository.kt index 3b59944..48931b7 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/repository/Repository.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/repository/Repository.kt @@ -1,6 +1,6 @@ -package com.appttude.h_mal.easycc.mvvm.data.repository +package com.appttude.h_mal.easycc.data.repository -import com.appttude.h_mal.easycc.mvvm.data.network.response.ResponseObject +import com.appttude.h_mal.easycc.data.network.response.ResponseObject /** * Main entry point for accessing currency data. diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/repository/RepositoryImpl.kt b/app/src/main/java/com/appttude/h_mal/easycc/data/repository/RepositoryImpl.kt similarity index 79% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/repository/RepositoryImpl.kt rename to app/src/main/java/com/appttude/h_mal/easycc/data/repository/RepositoryImpl.kt index 659784f..e08e90d 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/data/repository/RepositoryImpl.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/data/repository/RepositoryImpl.kt @@ -1,12 +1,12 @@ -package com.appttude.h_mal.easycc.mvvm.data.repository +package com.appttude.h_mal.easycc.data.repository import android.content.Context -import com.appttude.h_mal.easycc.mvvm.data.prefs.PreferenceProvider import com.appttude.h_mal.easycc.R -import com.appttude.h_mal.easycc.mvvm.data.network.response.ResponseObject -import com.appttude.h_mal.easycc.mvvm.data.network.SafeApiRequest -import com.appttude.h_mal.easycc.mvvm.data.network.api.CurrencyApi -import com.appttude.h_mal.easycc.mvvm.utils.convertPairsListToString +import com.appttude.h_mal.easycc.data.network.SafeApiRequest +import com.appttude.h_mal.easycc.data.network.api.CurrencyApi +import com.appttude.h_mal.easycc.data.network.response.ResponseObject +import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider +import com.appttude.h_mal.easycc.utils.convertPairsListToString /** * Default implementation of [Repository]. Single entry point for managing currency' data. diff --git a/app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidget.java b/app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidget.java deleted file mode 100644 index 412448c..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidget.java +++ /dev/null @@ -1,161 +0,0 @@ -package com.appttude.h_mal.easycc.legacy; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; -import android.text.TextUtils; -import android.util.Log; -import android.widget.RemoteViews; - -import com.appttude.h_mal.easycc.R; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.net.URL; - -import static com.appttude.h_mal.easycc.legacy.CurrencyAppWidgetConfigureActivity.loadTitlePref; -import static com.appttude.h_mal.easycc.legacy.PublicMethods.UriBuilder; -import static com.appttude.h_mal.easycc.legacy.PublicMethods.createUrl; -import static com.appttude.h_mal.easycc.legacy.PublicMethods.makeHttpRequest; -import static com.appttude.h_mal.easycc.legacy.PublicMethods.round; - -/** - * Implementation of App Widget functionality. - * App Widget Configuration implemented in {@link CurrencyAppWidgetConfigureActivity CurrencyAppWidgetConfigureActivity} - */ -public class CurrencyAppWidget extends AppWidgetProvider { - - static String LOG_TAG = CurrencyAppWidget.class.getSimpleName(); - - static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, - int appWidgetId) { - - String s1 = loadTitlePref(context,appWidgetId,0); - String s2 = loadTitlePref(context,appWidgetId,1); - - String URL = UriBuilder(s1,s2); - WidgetAsyncTask widgetAsyncTask = new WidgetAsyncTask(context,appWidgetId,appWidgetManager,s1.substring(0,3),s2.substring(0,3)); - widgetAsyncTask.execute(URL); - - } - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - // There may be multiple widgets active, so update all of them - for (int appWidgetId : appWidgetIds) { - updateAppWidget(context, appWidgetManager, appWidgetId); - } - } - - @Override - public void onDeleted(Context context, int[] appWidgetIds) { - // When the user deletes the widget, delete the preference associated with it. - for (int appWidgetId : appWidgetIds) { - CurrencyAppWidgetConfigureActivity.deleteTitlePref(context, appWidgetId); - } - } - - @Override - public void onEnabled(Context context) { - // Enter relevant functionality for when the first widget is created - } - - @Override - public void onDisabled(Context context) { - // Enter relevant functionality for when the last widget is disabled - } - - private static class WidgetAsyncTask extends AsyncTask { - - private Context context; - private int appWidgetId; - private AppWidgetManager appWidgetManager; - private String s1; - private String s2; - - public WidgetAsyncTask(Context context, int appWidgetId, AppWidgetManager appWidgetManager, String s1, String s2) { - this.context = context; - this.appWidgetId = appWidgetId; - this.appWidgetManager = appWidgetManager; - this.s1 = s1; - this.s2 = s2; - } - - @Override - protected Double doInBackground(String... urlString) { - String jsonResponse = null; - - if (urlString.length < 1 || urlString[0] == null) { - return null; - } - try { - URL url = createUrl(urlString[0]); - jsonResponse = makeHttpRequest(url); - - } catch (IOException e) { - Log.e(getClass().getSimpleName(), "Problem making the HTTP request.", e); - } - - - return extractFeatureFromJson(jsonResponse, s1, s2); - - } - - @Override - protected void onPostExecute(Double result) { - super.onPostExecute(result); - - RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.currency_app_widget); - views.setTextViewText(R.id.exchangeName, s1 + s2); - views.setTextViewText(R.id.exchangeRate, round(result,2)+""); - - float opacity = 0.3f; //opacity = 0: fully transparent, opacity = 1: no transparancy - int backgroundColor = 0x000000; //background color (here black) - views.setInt( R.id.widget_view, "setBackgroundColor", (int)(opacity * 0xFF) << 24 | backgroundColor); - - Intent clickIntentTemplate = new Intent(context, MainActivityJava.class); - - clickIntentTemplate.setAction(Intent.ACTION_MAIN); - clickIntentTemplate.addCategory(Intent.CATEGORY_LAUNCHER); - clickIntentTemplate.putExtra("parse_1",s1); - clickIntentTemplate.putExtra("parse_2",s2); - clickIntentTemplate.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); - - PendingIntent configPendingIntent = PendingIntent.getActivity(context, 0, clickIntentTemplate, PendingIntent.FLAG_UPDATE_CURRENT); - views.setOnClickPendingIntent(R.id.widget_view, configPendingIntent); - - // Instruct the widget manager to update the widget - appWidgetManager.updateAppWidget(appWidgetId, views); - - } - - private static double extractFeatureFromJson(String newsJSON, String s1, String s2) { - double conversionValue = 0.00; - - Log.i(LOG_TAG, "extractFeatureFromJson: " + newsJSON); - - Log.i(LOG_TAG, "extractFeatureFromJson: " + s1 + "_" + s2); - - if (TextUtils.isEmpty(newsJSON)) { - return 0.00; - } - - try { - JSONObject jObject = new JSONObject(newsJSON); - conversionValue = jObject.getDouble(s1 + "_" + s2); - - } catch (JSONException e) { - - Log.e("MainActivityJava", "Problem parsing the JSON results", e); - } - return conversionValue; - } - - } -} - diff --git a/app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidgetConfigureActivity.java b/app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidgetConfigureActivity.java deleted file mode 100644 index 13f5217..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/legacy/CurrencyAppWidgetConfigureActivity.java +++ /dev/null @@ -1,227 +0,0 @@ -package com.appttude.h_mal.easycc.legacy; - -import android.app.Activity; -import android.app.Dialog; -import android.appwidget.AppWidgetManager; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import androidx.annotation.NonNull; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.ListView; -import android.widget.TextView; - -import com.appttude.h_mal.easycc.R; - -/** - * The configuration screen for the {@link CurrencyAppWidget CurrencyAppWidget} AppWidget. - */ -public class CurrencyAppWidgetConfigureActivity extends Activity { - - private static final String PREFS_NAME = "com.example.haimalik.myapplication.CurrencyAppWidget"; - private static final String PREF_PREFIX_KEY = "appwidget_"; - private static final int PRIMARY = 0; - private static final int SECONDARY = 1; - int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; - - - View.OnClickListener mOnClickListener = new View.OnClickListener() { - public void onClick(View v) { - final Context context = CurrencyAppWidgetConfigureActivity.this; - - final Dialog dialog = new Dialog(context); - dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent); - dialog.setCancelable(false); - dialog.setContentView(R.layout.confirm_dialog); - - TextView text = (TextView) dialog.findViewById(R.id.confirm_text); - text.setText(new StringBuilder().append("Create widget for ") - .append(loadTitlePref(context, mAppWidgetId, PRIMARY)) - .append(loadTitlePref(context, mAppWidgetId, SECONDARY)) - .append("?").toString()); - - TextView yes = dialog.findViewById(R.id.confirm_yes); - yes.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - //do for yes - // It is the responsibility of the configuration activity to update the app widget - AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); - CurrencyAppWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId); - - // Make sure we pass back the original appWidgetId - Intent resultValue = new Intent(); - resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); - setResult(RESULT_OK, resultValue); - finish(); - } - }); - - TextView no = dialog.findViewById(R.id.confirm_no); - no.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - dialog.dismiss(); - } - }); - - dialog.show(); - - } - }; - - public CurrencyAppWidgetConfigureActivity() { - super(); - } - - // Write the prefix to the SharedPreferences object for this widget - static void saveCurrencyPref(Context context, int appWidgetId, String text, int item) { - SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit(); - prefs.putString(PREF_PREFIX_KEY + appWidgetId + "_" + item, text); - prefs.apply(); - } - - // Read the prefix from the SharedPreferences object for this widget. - // If there is no preference saved, get the default from a resource - public static String loadTitlePref(Context context, int appWidgetId, int item) { - SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, 0); - String titleValue = prefs.getString(PREF_PREFIX_KEY + appWidgetId + "_" + item, null); - if (titleValue != null) { - return titleValue; - } else { - return context.getResources().getStringArray(R.array.currency_arrays)[0].substring(0,3); - } - } - - static void deleteTitlePref(Context context, int appWidgetId) { - SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME, 0).edit(); - prefs.remove(PREF_PREFIX_KEY+ appWidgetId + "_0"); - prefs.remove(PREF_PREFIX_KEY+ appWidgetId + "_1"); - prefs.apply(); - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Set the result to CANCELED. This will cause the widget host to cancel - // out of the widget placement if the user presses the back button. - setResult(RESULT_CANCELED); - - setContentView(R.layout.currency_app_widget_configure); - - final TextView currencyOne = findViewById(R.id.currency_one); - final TextView currencyTwo = findViewById(R.id.currency_two); - TextView submit = findViewById(R.id.submit_widget); - - // Find the widget id from the intent. - Intent intent = getIntent(); - Bundle extras = intent.getExtras(); - if (extras != null) { - mAppWidgetId = extras.getInt( - AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); - } - - // If this activity was started with an intent without an app widget ID, finish with an error. - if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { - finish(); - return; - } - - - currencyOne.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - CustomDialogClass dialogClass = new CustomDialogClass(CurrencyAppWidgetConfigureActivity.this,currencyOne,PRIMARY); - dialogClass.show(); - } - }); - - - currencyTwo.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - CustomDialogClass dialogClass = new CustomDialogClass(CurrencyAppWidgetConfigureActivity.this,currencyTwo,SECONDARY); - dialogClass.show(); - } - }); - - submit.setOnClickListener(mOnClickListener); - - } - - private class CustomDialogClass extends Dialog implements android.view.View.OnClickListener{ - - Context context; - ListView listView; - TextView textView; - EditText editText; - int item; - - public CustomDialogClass(@NonNull Context context, TextView textView, int item) { - super(context); - this.context = context; - this.textView = textView; - this.item = item; - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.custom_dialog); - - getWindow().setBackgroundDrawableResource(android.R.color.transparent); - - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - - listView = (ListView) findViewById(R.id.list_view); - editText = (EditText) findViewById(R.id.search_text) ; - - final ArrayAdapter arrayAdapter = ArrayAdapter.createFromResource(context,R.array.currency_arrays,android.R.layout.simple_list_item_1); - listView.setAdapter(arrayAdapter); - - editText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - arrayAdapter.getFilter().filter(charSequence); - } - - @Override - public void afterTextChanged(Editable editable) { - - } - }); - - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - String text = adapterView.getItemAtPosition(i).toString().substring(0,3); - textView.setText(adapterView.getItemAtPosition(i).toString()); - saveCurrencyPref(context,mAppWidgetId,text,item); - dismiss(); - } - }); - } - - @Override - public void onClick(View view) { - - } - } - -} - diff --git a/app/src/main/java/com/appttude/h_mal/easycc/legacy/MainActivityJava.java b/app/src/main/java/com/appttude/h_mal/easycc/legacy/MainActivityJava.java deleted file mode 100644 index cab9e9e..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/legacy/MainActivityJava.java +++ /dev/null @@ -1,378 +0,0 @@ -package com.appttude.h_mal.easycc.legacy; - -import android.app.Dialog; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextUtils; -import android.text.TextWatcher; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.view.animation.AlphaAnimation; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import com.appttude.h_mal.easycc.R; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; -import java.net.URL; - -import java.text.DecimalFormat; - -import static com.appttude.h_mal.easycc.legacy.PublicMethods.UriBuilder; -import static com.appttude.h_mal.easycc.legacy.PublicMethods.createUrl; -import static com.appttude.h_mal.easycc.legacy.PublicMethods.makeHttpRequest; - -public class MainActivityJava extends AppCompatActivity { - - EditText currencyOneEditText; - EditText currencyTwoEditText; - TextView currencyOne; - TextView currencyTwo; - double conversionRateOne; - ProgressBar spinner; - LinearLayout wholeView; - - private String URL = "https://free.currencyconverterapi.com/api/v3/convert?"; - private String CURRENCY_ONE = "currency_one_pref"; - private String CURRENCY_TWO = "currency_two_pref"; - - private static final String LOG_TAG = MainActivityJava.class.getSimpleName(); - - SharedPreferences pref; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - pref = getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE); - this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); -// getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - - currencyOneEditText = (EditText) findViewById(R.id.topInsertValue); - currencyTwoEditText = (EditText) findViewById(R.id.bottomInsertValues); - - currencyOne = (TextView) findViewById(R.id.currency_one); - currencyTwo = (TextView) findViewById(R.id.currency_two); - - if (getIntent().getExtras() != null) { - Bundle b = getIntent().getExtras(); - currencyOne.setText(arrayEntry(b.getString("parse_1"))); - currencyTwo.setText(arrayEntry(b.getString("parse_2"))); - }else{ - if (pref != null) { - currencyOne.setText(pref.getString(CURRENCY_ONE, String.valueOf(getResources().getTextArray(R.array.currency_arrays)[0]))); - currencyTwo.setText(pref.getString(CURRENCY_TWO, String.valueOf(getResources().getTextArray(R.array.currency_arrays)[0]))); - }else{ - currencyOne.setText(getResources().getTextArray(R.array.currency_arrays)[0]); - currencyTwo.setText(getResources().getTextArray(R.array.currency_arrays)[0]); - } - } - - currencyOneEditText.addTextChangedListener(TextWatcherClass); - currencyTwoEditText.addTextChangedListener(TextWatcherClass2); - - spinner = (ProgressBar) findViewById(R.id.progressBar); - spinner.setVisibility(View.GONE); - - wholeView = findViewById(R.id.whole_view); - -// addListenerOnSpinnerItemSelection(); - - currencyOne.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - CustomDialogClass dialogClass = new CustomDialogClass(MainActivityJava.this,currencyOne); - dialogClass.show(); - } - }); - - currencyTwo.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - CustomDialogClass dialogClass = new CustomDialogClass(MainActivityJava.this,currencyTwo); - dialogClass.show(); - } - }); - - String stringURL = UriBuilder(currencyOne.getText().toString().substring(0,3), - currencyTwo.getText().toString().substring(0,3)); - MyAsyncTask task = new MyAsyncTask(); - task.execute(stringURL); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - if (getIntent().getExtras() != null) { - Bundle b = getIntent().getExtras(); - currencyOne.setText(arrayEntry(b.getString("parse_1"))); - currencyTwo.setText(arrayEntry(b.getString("parse_2"))); - } - } - - private TextWatcher TextWatcherClass = new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - currencyTwoEditText.removeTextChangedListener(TextWatcherClass2); - if(currencyOneEditText.getText().toString().isEmpty()){ - currencyTwoEditText.setText(""); - return; - } - - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - - try{ - - Double topValue = Double.parseDouble(currencyOneEditText.getText().toString()); - Double bottomValue = topValue * conversionRateOne; - DecimalFormat df = new DecimalFormat("#.##"); - bottomValue = Double.valueOf(df.format(bottomValue)); - currencyTwoEditText.setText(bottomValue.toString()); - - } - catch (NumberFormatException e){ - Log.e(LOG_TAG, "no numbers inserted"); - } - currencyTwoEditText.addTextChangedListener(TextWatcherClass2); - } - - }; - - private TextWatcher TextWatcherClass2 = new TextWatcher() { - - @Override - public void onTextChanged(CharSequence s, int start, int before, - int count) { - currencyOneEditText.removeTextChangedListener(TextWatcherClass); - if(currencyTwoEditText.getText().toString().isEmpty()){ - currencyOneEditText.setText(""); - } - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, - int after) { - } - - @Override - public void afterTextChanged(Editable s) { - - try{ - - Double bottomValue = Double.parseDouble(currencyTwoEditText.getText().toString()); - Double topValue = bottomValue * (1 / conversionRateOne); - DecimalFormat df = new DecimalFormat("#.##"); - topValue = Double.valueOf(df.format(topValue)); - currencyOneEditText.setText(topValue.toString()); - - - } - catch (NumberFormatException e){ - Log.e(LOG_TAG, "no numbers inserted"); - } - currencyOneEditText.addTextChangedListener(TextWatcherClass); - } - - }; - - - - private double extractFeatureFromJson(String newsJSON) { - double conversionValue = 0.00; - - Log.i(LOG_TAG, "extractFeatureFromJson: " + newsJSON); - - String currencyOneVal = currencyOne.getText().toString().substring(0,3); - String currencyTwoVal = currencyTwo.getText().toString().substring(0,3); - - Log.i(LOG_TAG, "extractFeatureFromJson: " + currencyOneVal + "_" + currencyTwoVal); - - if (TextUtils.isEmpty(newsJSON)) { - return 0.00; - } - - try { - JSONObject jObject = new JSONObject(newsJSON); - conversionValue = jObject.getDouble(currencyOneVal + "_" + currencyTwoVal); - - } catch (JSONException e) { - - Log.e("MainActivityJava", "Problem parsing the JSON results", e); - } - return conversionValue; - } - - class MyAsyncTask extends AsyncTask { - - @Override - public Double doInBackground(String... urlString) { - String jsonResponse = null; - - if (urlString.length < 1 || urlString[0] == null) { - return null; - } - try { - URL url = createUrl(urlString[0]); - jsonResponse = makeHttpRequest(url); - - } catch (IOException e) { - Log.e(LOG_TAG, "Problem making the HTTP request.", e); - } - - if (jsonResponse.equals("")){ - return null; - } - - return extractFeatureFromJson(jsonResponse); - - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - spinner.setVisibility(View.VISIBLE); - AlphaAnimation animation1 = new AlphaAnimation(1.0f, 0.2f); - animation1.setDuration(200); - wholeView.startAnimation(animation1); - wholeView.setAlpha(0.2f); - } - - @Override - protected void onPostExecute(Double result) { - super.onPostExecute(result); - - spinner.setVisibility(View.GONE); - wholeView.setAlpha(1.0f); - - if (result == null){ - Toast.makeText(MainActivityJava.this, "Failed to retrieve exchange rate", Toast.LENGTH_SHORT).show(); - }else{ - conversionRateOne = result; - } - - } - - } - - private class CustomDialogClass extends Dialog implements android.view.View.OnClickListener{ - - Context context; - ListView listView; - TextView textView; - EditText editText; - int selection; - - public CustomDialogClass(@NonNull Context context, TextView textView) { - super(context); - this.context = context; - this.textView = textView; - if (textView.getId() == R.id.currency_one){ - selection = 1; - }else{ - selection = 2; - } - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.custom_dialog); - - getWindow().setBackgroundDrawableResource(android.R.color.transparent); - - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - - listView = (ListView) findViewById(R.id.list_view); - editText = (EditText) findViewById(R.id.search_text) ; - - final ArrayAdapter arrayAdapter = ArrayAdapter.createFromResource(context,R.array.currency_arrays,android.R.layout.simple_list_item_1); - listView.setAdapter(arrayAdapter); - - editText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - arrayAdapter.getFilter().filter(charSequence); - } - - @Override - public void afterTextChanged(Editable editable) { - - } - }); - - listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int i, long l) { - textView.setText(adapterView.getItemAtPosition(i).toString()); - SharedPreferences.Editor editor = pref.edit(); - if (selection == 1) { - editor.putString(CURRENCY_ONE,adapterView.getItemAtPosition(i).toString()); - }else{ - editor.putString(CURRENCY_TWO,adapterView.getItemAtPosition(i).toString()); - } - editor.apply(); - currencyOneEditText.setText(""); - currencyTwoEditText.setText(""); - String stringURL = UriBuilder(currencyOne.getText().toString().substring(0,3), - currencyTwo.getText().toString().substring(0,3)); - MyAsyncTask task = new MyAsyncTask(); - task.execute(stringURL); - dismiss(); - } - }); - } - - @Override - public void onClick(View view) { - - } - } - - private String arrayEntry (String s){ - String[] strings = getResources().getStringArray(R.array.currency_arrays); - String returnString = strings[0]; - for (String string : strings) { - if (s.equals(string.substring(0, 3))) { - returnString = string; - - } - } - - return returnString; - } - - -} diff --git a/app/src/main/java/com/appttude/h_mal/easycc/legacy/PublicMethods.java b/app/src/main/java/com/appttude/h_mal/easycc/legacy/PublicMethods.java deleted file mode 100644 index a60d2e6..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/legacy/PublicMethods.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.appttude.h_mal.easycc.legacy; - -import android.net.Uri; -import android.util.Log; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.Charset; - -public class PublicMethods { - - private static String TAG = PublicMethods.class.getSimpleName(); - private static String URL = "https://free.currencyconverterapi.com/api/v3/convert?"; - - public PublicMethods() { - } - - public static String UriBuilder(String s1, String s2){ - s1 = s1.substring(0,3); - s2 = s2.substring(0,3); - - Uri baseUri = Uri.parse(URL); - Uri.Builder builder = baseUri.buildUpon(); - builder.appendQueryParameter("q", s1 + "_" + s2) - .appendQueryParameter("compact", "ultra") - .appendQueryParameter("apiKey", "a4f93cc2ff05dd772321"); - - return builder.build().toString(); - - } - - public static java.net.URL createUrl(String stringUrl) { - URL url = null; - try { - url = new URL(stringUrl); - } catch (MalformedURLException e) { - Log.e(TAG, "Error with creating URL ", e); - } - return url; - } - - - public static String makeHttpRequest(URL url) throws IOException { - String jsonResponse = ""; - - if (url == null) { - return jsonResponse; - } - - HttpURLConnection urlConnection = null; - InputStream inputStream = null; - try { - urlConnection = (HttpURLConnection) url.openConnection(); - urlConnection.setReadTimeout(30000); - urlConnection.setConnectTimeout(30000); - urlConnection.setRequestMethod("GET"); - urlConnection.connect(); - - if (urlConnection.getResponseCode() == 200) { - inputStream = urlConnection.getInputStream(); - jsonResponse = readFromStream(inputStream); - } else { - Log.e(TAG, "Error response code: " + urlConnection.getResponseCode()); - } - } catch (IOException e) { - Log.e(TAG, "Problem retrieving the JSON results.", e); - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - if (inputStream != null) { - inputStream.close(); - } - } - return jsonResponse; - } - - private static String readFromStream(InputStream inputStream) throws IOException { - StringBuilder output = new StringBuilder(); - if (inputStream != null) { - InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8")); - BufferedReader reader = new BufferedReader(inputStreamReader); - String line = ""; - while (line != null) { - output.append(line); - line = reader.readLine(); - } - } - Log.d(TAG, output.toString()); - return output.toString(); - - } - - public static double round(double value, int places) { - if (places < 0) throw new IllegalArgumentException(); - - long factor = (long) Math.pow(10, places); - value = value * factor; - long tmp = Math.round(value); - return (double) tmp / factor; - } - -} diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/models/CurrencyObject.kt b/app/src/main/java/com/appttude/h_mal/easycc/models/CurrencyObject.kt similarity index 86% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/models/CurrencyObject.kt rename to app/src/main/java/com/appttude/h_mal/easycc/models/CurrencyObject.kt index 567522c..94ec653 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/models/CurrencyObject.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/models/CurrencyObject.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.models +package com.appttude.h_mal.easycc.models import com.google.gson.annotations.SerializedName diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/RateListener.kt b/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/RateListener.kt deleted file mode 100644 index e371bae..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/RateListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.appttude.h_mal.easycc.mvvm.ui.app - -interface RateListener { - fun onStarted() - fun onSuccess() - fun onFailure(message: String) -} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt b/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt deleted file mode 100644 index 7a157a2..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt +++ /dev/null @@ -1,70 +0,0 @@ -package com.appttude.h_mal.easycc.mvvm.ui.widget - -import android.appwidget.AppWidgetManager -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import androidx.databinding.DataBindingUtil -import androidx.lifecycle.ViewModelProviders -import com.appttude.h_mal.easycc.R -import com.appttude.h_mal.easycc.databinding.CurrencyAppWidgetConfigureBinding -import com.appttude.h_mal.easycc.mvvm.ui.app.RateListener -import com.appttude.h_mal.easycc.mvvm.utils.DisplayToast -import org.kodein.di.KodeinAware -import org.kodein.di.android.kodein -import org.kodein.di.generic.instance - -/** - * The configuration screen for the [CurrencyAppWidgetKotlin] AppWidget. - */ -class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAware, RateListener { - - override val kodein by kodein() - private val factory : WidgetViewModelFactory by instance() - - var mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID - - companion object{ - lateinit var viewModel: WidgetViewModel - } - - public override fun onCreate(icicle: Bundle?) { - super.onCreate(icicle) - - // Set the result to CANCELED. This will cause the widget host to cancel - // out of the widget placement if the user presses the back button. - setResult(RESULT_CANCELED) - - // Find the widget id from the intent. - val extras = intent.extras - if (extras != null) { - mAppWidgetId = extras.getInt( - AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) - } - - // If this activity was started with an intent without an app widget ID, finish with an error. - if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { - finish() - return - } - - viewModel = ViewModelProviders.of(this, factory).get(WidgetViewModel::class.java) - val binding: CurrencyAppWidgetConfigureBinding = DataBindingUtil.setContentView(this, R.layout.currency_app_widget_configure) - binding.viewmodel = viewModel - binding.lifecycleOwner = this - - viewModel.initialise(mAppWidgetId) - viewModel.rateListener = this - - } - - override fun onStarted() {} - - override fun onSuccess() { - WidgetSubmitDialog(this,mAppWidgetId, viewModel).show() - } - - override fun onFailure(message: String) { - DisplayToast(message) - } - -} diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetSubmitDialog.kt b/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetSubmitDialog.kt deleted file mode 100644 index e8f84de..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetSubmitDialog.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.appttude.h_mal.easycc.mvvm.ui.widget - -import android.app.Activity -import android.app.Dialog -import android.appwidget.AppWidgetManager -import android.content.Intent -import android.os.Bundle -import com.appttude.h_mal.easycc.R -import com.appttude.h_mal.easycc.mvvm.utils.transformIntToArray -import kotlinx.android.synthetic.main.confirm_dialog.* - - -/** - * Dialog created when submitting the completed selections - * in [CurrencyAppWidgetConfigureActivityKotlin] - */ -class WidgetSubmitDialog( - private val activity: Activity, - private val appWidgetId: Int, - private val viewModel: WidgetViewModel -) :Dialog(activity){ - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.confirm_dialog) - // layer behind dialog to be transparent - window!!.setBackgroundDrawableResource(android.R.color.transparent) - // Dialog cannot be cancelled by clicking away - setCancelable(false) - - confirm_text.text = StringBuilder().append("Create widget for ") - .append(viewModel.getWidgetStringName()) - .append("?").toString() - - confirm_yes.setOnClickListener { - // It is the responsibility of the configuration activity to update the app widget - // Send update broadcast to widget app class - Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, - null, - context, - CurrencyAppWidgetKotlin::class.java).apply { - // Save current widget pairs - viewModel.setWidgetStored() - // Put current app widget ID into extras and send broadcast - putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, transformIntToArray(appWidgetId) ) - activity.sendBroadcast(this) - } - - - // Make sure we pass back the original appWidgetId - val resultValue = activity.intent - resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) - activity.setResult(Activity.RESULT_OK, resultValue) - activity.finish() - } - - confirm_no.setOnClickListener { dismiss() } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModel.kt b/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModel.kt deleted file mode 100644 index 8576a2e..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModel.kt +++ /dev/null @@ -1,83 +0,0 @@ -package com.appttude.h_mal.easycc.mvvm.ui.widget - -import android.view.View -import android.widget.Toast -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl -import com.appttude.h_mal.easycc.mvvm.ui.app.RateListener - -class WidgetViewModel( - private val repository: RepositoryImpl -) : ViewModel(){ - - var rateListener: RateListener? = null - - var appWidgetId: Int? = null - - var rateIdFrom = MutableLiveData() - var rateIdTo = MutableLiveData() - - fun initialise(appId: Int){ - appWidgetId = appId - val widgetString = getWidgetStored(appId) - - rateIdFrom.value = widgetString.first - rateIdTo.value = widgetString.second - - } - - fun selectCurrencyOnClick(view: View){ - if (appWidgetId == null){ - Toast.makeText(view.context, "No App Widget ID", Toast.LENGTH_LONG).show() - return - } - - WidgetItemSelectDialog(view.context, object : DialogResult { - override fun result(result: String) { - if (view.tag.toString() == "top"){ - rateIdFrom.value = result - }else{ - rateIdTo.value = result - } - Toast.makeText(view.context, result, Toast.LENGTH_LONG).show() - } - }).show() - } - - fun submitSelectionOnClick(view: View){ - if (appWidgetId == null){ - rateListener?.onFailure("No App Widget ID") - return - } - - if (rateIdFrom.value == rateIdTo.value){ - rateListener?.onFailure("Selected rates cannot be the same") - return - } - - rateListener?.onSuccess() - } - - fun getWidgetStored(id: Int) = repository.getWidgetConversionPairs(id) - - fun setWidgetStored() { - if (rateIdTo.value == null && rateIdFrom.value == null){ - rateListener?.onFailure("Selections incomplete") - return - } - - if (rateIdFrom.value == rateIdTo.value){ - rateListener?.onFailure("Selected rates cannot be the same") - return - } - - repository.setWidgetConversionPairs(rateIdFrom.value!!,rateIdTo.value!!,appWidgetId!!) - } - - fun getWidgetStringName() = "${rateIdFrom.value!!.trimToThree()}${rateIdTo.value!!.trimToThree()}" - - private fun String.trimToThree() = this.substring(0,3) - - -} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/PrimitiveUtils.kt b/app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/PrimitiveUtils.kt deleted file mode 100644 index 0eab21e..0000000 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/PrimitiveUtils.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.appttude.h_mal.easycc.mvvm.utils - -import java.text.DecimalFormat - -fun transformIntToArray(int: Int): IntArray{ - return intArrayOf(int) -} - -fun String.trimToThree(): String{ - if (this.length > 3){ - return this.substring(0, 3) - } - return this -} - -fun convertPairsListToString(s1: String, s2: String): String = - "${s1.trimToThree()}_${s2.trimToThree()}" - -fun Double.toTwoDp() = run { - val df = DecimalFormat("#.##") - java.lang.Double.valueOf(df.format(this)) -} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/CustomDialogClass.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/CustomDialogClass.kt similarity index 80% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/CustomDialogClass.kt rename to app/src/main/java/com/appttude/h_mal/easycc/ui/main/CustomDialogClass.kt index ae1d70e..1ffd9d1 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/CustomDialogClass.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/CustomDialogClass.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.ui.app +package com.appttude.h_mal.easycc.ui.main import android.app.Dialog import android.content.Context @@ -10,6 +10,9 @@ import android.widget.ArrayAdapter import com.appttude.h_mal.easycc.R import kotlinx.android.synthetic.main.custom_dialog.* +/** + * Custom dialog when selecting currencies from list with filter + */ class CustomDialogClass( context: Context, private val clickListener: ClickListener @@ -19,9 +22,12 @@ class CustomDialogClass( super.onCreate(savedInstanceState) setContentView(R.layout.custom_dialog) + // Transparent background window!!.setBackgroundDrawableResource(android.R.color.transparent) + // Keyboard not to overlap dialog window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) + // array adapter for list of currencies in R.Strings val arrayAdapter = ArrayAdapter.createFromResource( context, R.array.currency_arrays, @@ -29,6 +35,7 @@ class CustomDialogClass( list_view.adapter = arrayAdapter + // Edit text to filter @arrayAdapter search_text.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { @@ -37,6 +44,7 @@ class CustomDialogClass( override fun afterTextChanged(editable: Editable) {} }) + // interface selection back to calling activity list_view.setOnItemClickListener{ adapterView, _, i, _ -> clickListener.onText(adapterView.getItemAtPosition(i).toString()) dismiss() @@ -44,6 +52,7 @@ class CustomDialogClass( } } +// Interface to handle selection within dialog interface ClickListener{ fun onText(currencyName: String) } \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainActivity.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainActivity.kt similarity index 82% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainActivity.kt rename to app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainActivity.kt index 874b382..a8c6902 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainActivity.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainActivity.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.ui.app +package com.appttude.h_mal.easycc.ui.main import android.os.Bundle import android.text.Editable @@ -12,15 +12,15 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders import com.appttude.h_mal.easycc.R import com.appttude.h_mal.easycc.databinding.ActivityMainBinding -import com.appttude.h_mal.easycc.mvvm.utils.DisplayToast -import com.appttude.h_mal.easycc.mvvm.utils.clearEditText -import com.appttude.h_mal.easycc.mvvm.utils.hideView +import com.appttude.h_mal.easycc.utils.clearEditText +import com.appttude.h_mal.easycc.utils.displayToast +import com.appttude.h_mal.easycc.utils.hideView import kotlinx.android.synthetic.main.activity_main.* import org.kodein.di.KodeinAware import org.kodein.di.android.kodein import org.kodein.di.generic.instance -class MainActivity : AppCompatActivity(), RateListener, KodeinAware, View.OnClickListener { +class MainActivity : AppCompatActivity(), KodeinAware, View.OnClickListener { override val kodein by kodein() // Retrieve MainViewModelFactory via dependency injection @@ -56,15 +56,19 @@ class MainActivity : AppCompatActivity(), RateListener, KodeinAware, View.OnClic private fun setUpObservers() { viewModel.operationStartedListener.observe(this, Observer { + // Show progress bar progressBar.hideView(false) }) viewModel.operationFinishedListener.observe(this, Observer { pair -> + // hide progress bar progressBar.hideView(true) if (pair.first){ + // Operation was successful remove text in EditTexts bottomInsertValues.clearEditText() topInsertValue.clearEditText() }else{ - pair.second?.let { DisplayToast(it) } + // Display Toast with error message returned from Viewmodel + pair.second?.let { displayToast(it) } } }) } @@ -78,38 +82,25 @@ class MainActivity : AppCompatActivity(), RateListener, KodeinAware, View.OnClic } private fun showCustomDialog(view: View?) { - - val dialogClass = CustomDialogClass(this, object : ClickListener { + CustomDialogClass(this, object : ClickListener { override fun onText(currencyName: String) { (view as TextView).text = currencyName viewModel.setCurrencyName(view.tag, currencyName) } - }) - dialogClass.show() - } - override fun onStarted() { - progressBar.hideView(false) - } - - override fun onSuccess() { - progressBar.hideView(true) - bottomInsertValues.clearEditText() - topInsertValue.clearEditText() - } - - override fun onFailure(message: String) { - progressBar.hideView(true) - DisplayToast(message) + }).show() } override fun onClick(view: View?) { showCustomDialog(view) } + // Text watcher applied to EditText @topInsertValue private val textWatcherClass: TextWatcher = object : TextWatcher { override fun onTextChanged(s: CharSequence, st: Int, b: Int, c: Int) { + // Remove text watcher on other text watcher to prevent infinite loop bottomInsertValues.removeTextChangedListener(textWatcherClass2) + // Clear any values if current EditText is empty if (topInsertValue.text.isNullOrEmpty()) bottomInsertValues.setText("") } @@ -117,12 +108,14 @@ class MainActivity : AppCompatActivity(), RateListener, KodeinAware, View.OnClic override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun afterTextChanged(s: Editable) { bottomInsertValues.setText(viewModel.getConversion(s.toString())) + // add Text watcher back as it is safe to do so bottomInsertValues.addTextChangedListener(textWatcherClass2) } } private val textWatcherClass2: TextWatcher = object : TextWatcher { override fun onTextChanged(s: CharSequence, st: Int, b: Int, c: Int) { + topInsertValue.removeTextChangedListener(textWatcherClass) if (bottomInsertValues.text.isNullOrEmpty()) topInsertValue.clearEditText() diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainViewModel.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainViewModel.kt similarity index 64% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainViewModel.kt rename to app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainViewModel.kt index 1526bd7..6e2565a 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainViewModel.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainViewModel.kt @@ -1,26 +1,28 @@ -package com.appttude.h_mal.easycc.mvvm.ui.app +package com.appttude.h_mal.easycc.ui.main import android.os.Bundle import android.util.Log -import android.widget.EditText import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.appttude.h_mal.easycc.mvvm.data.repository.Repository -import com.appttude.h_mal.easycc.mvvm.utils.toTwoDp -import kotlinx.android.synthetic.main.activity_main.* +import com.appttude.h_mal.easycc.data.repository.Repository +import com.appttude.h_mal.easycc.utils.toTwoDpString import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.io.IOException -import java.text.DecimalFormat +/** + * ViewModel for the task Main Activity Screen + */ private const val TAG = "MainViewModel" class MainViewModel( + // Repository injected via Viewmodel factory private val repository: Repository ) : ViewModel(){ private val conversionPairs by lazy { repository.getConversionPair() } + // Viewbinding to textviews in @activity_main.xml var rateIdFrom: String? = null var rateIdTo: String? = null @@ -30,36 +32,42 @@ class MainViewModel( private var conversionRate: Double = 0.00 - fun getExchangeRate(){ - - operationStartedListener.postValue(false) + private fun getExchangeRate(){ + operationStartedListener.postValue(true) + // Null check on currency values if (rateIdFrom.isNullOrEmpty() || rateIdTo.isNullOrEmpty()){ operationFinishedListener.postValue(Pair(false, "Select currencies")) return } + // No need to call api as it will return exchange rate as 1 if (rateIdFrom == rateIdTo){ conversionRate = 1.00 operationFinishedListener.postValue(Pair(true, null)) return } + // Open Coroutine on IO thread to carry out async task CoroutineScope(Dispatchers.IO).launch { try { + // Non-null assertion (!!) as values have been null checked and have not changed val exchangeResponse = repository.getData(rateIdFrom!!, rateIdTo!!) - repository.setConversionPair(rateIdFrom!!, rateIdTo!!) exchangeResponse.results?.iterator()?.next()?.value?.let { + // Response Successful and contains @param CurrencyObject + repository.setConversionPair(rateIdFrom!!, rateIdTo!!) + operationFinishedListener.postValue(Pair(true, null)) conversionRate = it.value return@launch } }catch(e: IOException){ - operationFinishedListener.postValue(Pair(false, e.message ?: "Currency Retrieval failed")) - return@launch + e.message?.let { + operationFinishedListener.postValue(Pair(false, it)) + return@launch + } } - operationFinishedListener.postValue(Pair(false, "Failed to retrieve rate")) } } @@ -67,8 +75,8 @@ class MainViewModel( fun getConversion(fromValue: String): String? { return try { val fromValDouble = fromValue.toDouble() - val bottomVal1 = (fromValDouble * conversionRate).toTwoDp() - bottomVal1.toBigDecimal().toPlainString() + val bottomVal1 = (fromValDouble * conversionRate) + bottomVal1.toTwoDpString() }catch (e: NumberFormatException) { Log.e(TAG, "no numbers inserted") null @@ -78,23 +86,26 @@ class MainViewModel( fun getReciprocalConversion(toValue: String): String? { return try { val toDoubleVal = toValue.toDouble() - val newTopVal = toDoubleVal.times((1/conversionRate)).toTwoDp() - newTopVal.toBigDecimal().toPlainString() + val newTopVal = toDoubleVal.times((1/conversionRate)) + newTopVal.toTwoDpString() } catch (e: NumberFormatException) { Log.e(TAG, "no numbers inserted") null } } + // Start operation based on dialog selection fun setCurrencyName(tag: Any?, currencyName: String){ - if (tag.toString() == "top"){ - rateIdFrom = currencyName - }else{ - rateIdTo = currencyName + when(tag.toString()){ + "top" -> rateIdFrom = currencyName + "bottom" -> rateIdTo = currencyName + else -> { return } } + getExchangeRate() } + // Start operation based on possible values stored in bundle or retrieve from repository fun initiate(extras: Bundle?) { rateIdFrom = extras?.getString("parse_1") ?: conversionPairs.first rateIdTo = extras?.getString("parse_2") ?: conversionPairs.second diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainViewModelFactory.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainViewModelFactory.kt similarity index 64% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainViewModelFactory.kt rename to app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainViewModelFactory.kt index 49766a4..15a2d4f 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/app/MainViewModelFactory.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/main/MainViewModelFactory.kt @@ -1,9 +1,13 @@ -package com.appttude.h_mal.easycc.mvvm.ui.app +package com.appttude.h_mal.easycc.ui.main import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl +import com.appttude.h_mal.easycc.data.repository.RepositoryImpl +/** + * Viewmodel factory for [MainViewModel] + * inject repository into viewmodel + */ @Suppress("UNCHECKED_CAST") class MainViewModelFactory ( private val repository: RepositoryImpl diff --git a/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt new file mode 100644 index 0000000..69d936b --- /dev/null +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/CurrencyAppWidgetConfigureActivityKotlin.kt @@ -0,0 +1,151 @@ +package com.appttude.h_mal.easycc.ui.widget + +import android.app.Activity +import android.appwidget.AppWidgetManager +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.DataBindingUtil +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProviders +import com.appttude.h_mal.easycc.R +import com.appttude.h_mal.easycc.databinding.CurrencyAppWidgetConfigureBinding +import com.appttude.h_mal.easycc.ui.main.ClickListener +import com.appttude.h_mal.easycc.ui.main.CustomDialogClass +import com.appttude.h_mal.easycc.utils.displayToast +import com.appttude.h_mal.easycc.utils.transformIntToArray +import com.appttude.h_mal.easycc.widget.CurrencyAppWidgetKotlin +import kotlinx.android.synthetic.main.currency_app_widget_configure.* +import org.kodein.di.KodeinAware +import org.kodein.di.android.kodein +import org.kodein.di.generic.instance + +/** + * The configuration screen for the [CurrencyAppWidgetKotlin] AppWidget. + */ +class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAware, View.OnClickListener { + + override val kodein by kodein() + private val factory: WidgetViewModelFactory by instance() + + var mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + + companion object { + lateinit var viewModel: WidgetViewModel + } + + public override fun onCreate(icicle: Bundle?) { + super.onCreate(icicle) + + // Set the result to CANCELED. This will cause the widget host to cancel + // out of the widget placement if the user presses the back button. + setResult(RESULT_CANCELED) + + // Find the widget id from the intent. + val extras = intent.extras + if (extras != null) { + mAppWidgetId = extras.getInt( + AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID) + } + + // If this activity was started with an intent without an app widget ID, finish with an error. + if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + finish() + return + } + + // ViewModel setup + viewModel = ViewModelProviders.of(this, factory).get(WidgetViewModel::class.java) + viewModel.initiate(mAppWidgetId) + + setupDataBinding() + setupObserver() + setupClickListener() + } + + private fun setupClickListener() { + submit_widget.setOnClickListener(this) + currency_one.setOnClickListener(this) + currency_two.setOnClickListener(this) + } + + private fun setupObserver() { + viewModel.operationFinishedListener.observe(this, Observer { + + // it.first is a the success of the operation + if (it.first){ + displaySubmitDialog() + }else{ + // failed operation - display toast with message from it.second + it.second?.let { message -> displayToast(message) } + } + }) + } + + private fun setupDataBinding() { + // data binding to @R.layout.currency_app_widget_configure + DataBindingUtil.setContentView( + this, + R.layout.currency_app_widget_configure + ).apply { + viewmodel = viewModel + lifecycleOwner = this@CurrencyAppWidgetConfigureActivityKotlin + } + } + + override fun onClick(view: View?) { + when (view?.tag.toString()) { + "top", "bottom" -> showCustomDialog(view) + "submit" -> viewModel.submitSelectionOnClick() + else -> { + return + } + } + } + + private fun displaySubmitDialog() { + val message = viewModel.getSubmitDialogMessage() + WidgetSubmitDialog(this, message, object : DialogSubmit { + override fun onSubmit() { + sendUpdateIntent() + finishCurrencyWidgetActivity() + } + }).show() + } + + + private fun showCustomDialog(view: View?) { + CustomDialogClass(this, object : ClickListener { + override fun onText(currencyName: String) { + (view as TextView).text = currencyName + viewModel.setCurrencyName(view.tag, currencyName) + } + }).show() + } + + fun finishCurrencyWidgetActivity(){ + // Make sure we pass back the original appWidgetId + val resultValue = intent + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId) + setResult(Activity.RESULT_OK, resultValue) + finish() + } + + fun sendUpdateIntent() { + // It is the responsibility of the configuration activity to update the app widget + // Send update broadcast to widget app class + Intent(this@CurrencyAppWidgetConfigureActivityKotlin, + CurrencyAppWidgetKotlin::class.java + ).apply { + action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + viewModel.setWidgetStored() + + // Put current app widget ID into extras and send broadcast + putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, transformIntToArray(mAppWidgetId)) + sendBroadcast(this) + } + } + +} diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetItemSelectDialog.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetItemSelectDialog.kt similarity index 94% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetItemSelectDialog.kt rename to app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetItemSelectDialog.kt index feda086..22e4262 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetItemSelectDialog.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetItemSelectDialog.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.ui.widget +package com.appttude.h_mal.easycc.ui.widget import android.app.Dialog import android.content.Context @@ -15,7 +15,7 @@ widget for when submitting the completed selections */ class WidgetItemSelectDialog( context: Context, - val dialogResult: DialogResult + private val dialogResult: DialogResult ) :Dialog(context){ override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetSubmitDialog.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetSubmitDialog.kt new file mode 100644 index 0000000..f23ba77 --- /dev/null +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetSubmitDialog.kt @@ -0,0 +1,38 @@ +package com.appttude.h_mal.easycc.ui.widget + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import com.appttude.h_mal.easycc.R +import kotlinx.android.synthetic.main.confirm_dialog.* + + +/** + * Dialog created when submitting the completed selections + * in [CurrencyAppWidgetConfigureActivityKotlin] + */ +class WidgetSubmitDialog( + context: Context, + private val messageString: String, + private val dialogInterface: DialogSubmit +) :Dialog(context){ + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.confirm_dialog) + // layer behind dialog to be transparent + window!!.setBackgroundDrawableResource(android.R.color.transparent) + // Dialog cannot be cancelled by clicking away + setCancelable(false) + + confirm_text.text = messageString + + // handle dialog buttons + confirm_yes.setOnClickListener { dialogInterface.onSubmit() } + confirm_no.setOnClickListener { dismiss() } + } +} + +interface DialogSubmit{ + fun onSubmit() +} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModel.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModel.kt new file mode 100644 index 0000000..1443614 --- /dev/null +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModel.kt @@ -0,0 +1,70 @@ +package com.appttude.h_mal.easycc.ui.widget + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.appttude.h_mal.easycc.data.repository.Repository +import com.appttude.h_mal.easycc.utils.trimToThree + +class WidgetViewModel( + private val repository: Repository +) : ViewModel(){ + + private val defaultCurrency: String by lazy { repository.getArrayList()[0] } + var appWidgetId: Int? = null + + // data binding to @R.layout.currency_app_widget_configure + var rateIdFrom: String? = null + var rateIdTo: String? = null + + // Live data to feedback to @CurrencyAppWidgetConfigureActivityKotlin + val operationFinishedListener = MutableLiveData>() + + // Setup viewmodel app widget ID + // Set default values for text views + fun initiate(appId: Int){ + appWidgetId = appId + val widgetString + = repository.getWidgetConversionPairs(appId) + + rateIdFrom = widgetString.first ?: defaultCurrency + rateIdTo = widgetString.second ?: defaultCurrency + + } + + // 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){ + operationFinishedListener.value = Pair(false, "Selections incomplete") + return + } + if (rateIdFrom == rateIdTo){ + operationFinishedListener.value = + Pair(false, "Selected rates cannot be the same ${rateIdFrom}${rateIdTo}") + return + } + operationFinishedListener.value = Pair(true, null) + } + + fun setWidgetStored() { + repository.setWidgetConversionPairs(rateIdFrom!!,rateIdTo!!,appWidgetId!!) + } + + // Start operation based on dialog selection + fun setCurrencyName(tag: Any?, currencyName: String){ + when(tag.toString()){ + "top" -> rateIdFrom = currencyName + "bottom" -> rateIdTo = currencyName + else -> { return } + } + } + + private fun getWidgetStringName() = "${rateIdFrom!!.trimToThree()}${rateIdTo!!.trimToThree()}" + +} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModelFactory.kt b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModelFactory.kt similarity index 74% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModelFactory.kt rename to app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModelFactory.kt index 5d90697..97b373c 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/WidgetViewModelFactory.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/ui/widget/WidgetViewModelFactory.kt @@ -1,8 +1,8 @@ -package com.appttude.h_mal.easycc.mvvm.ui.widget +package com.appttude.h_mal.easycc.ui.widget import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl +import com.appttude.h_mal.easycc.data.repository.RepositoryImpl @Suppress("UNCHECKED_CAST") class WidgetViewModelFactory ( diff --git a/app/src/main/java/com/appttude/h_mal/easycc/utils/PrimitiveUtils.kt b/app/src/main/java/com/appttude/h_mal/easycc/utils/PrimitiveUtils.kt new file mode 100644 index 0000000..9bb12ef --- /dev/null +++ b/app/src/main/java/com/appttude/h_mal/easycc/utils/PrimitiveUtils.kt @@ -0,0 +1,36 @@ +package com.appttude.h_mal.easycc.utils + +import java.lang.Double.valueOf +import java.text.DecimalFormat +import java.util.* + +fun transformIntToArray(int: Int): IntArray{ + return intArrayOf(int) +} + +fun String.trimToThree(): String{ + val size = length + return when { + size > 3 -> substring(0, 3) + else -> this + } +} + +fun convertPairsListToString(s1: String, s2: String): String = + "${s1.trimToThree()}_${s2.trimToThree()}" + +fun Double.toTwoDp() = run { + try { + val df = DecimalFormat("0.00") + df.currency = Currency.getInstance(Locale.getDefault()) + valueOf(df.format(this)) + }catch (e: NumberFormatException){ + e.printStackTrace() + this + } + +} + +fun Double.toTwoDpString(): String{ + return this.toTwoDp().toBigDecimal().toPlainString() +} \ No newline at end of file diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/ViewUtils.kt b/app/src/main/java/com/appttude/h_mal/easycc/utils/ViewUtils.kt similarity index 78% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/ViewUtils.kt rename to app/src/main/java/com/appttude/h_mal/easycc/utils/ViewUtils.kt index 448fd17..78c82b4 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/utils/ViewUtils.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/utils/ViewUtils.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.utils +package com.appttude.h_mal.easycc.utils import android.content.Context import android.view.View @@ -13,6 +13,6 @@ fun View.hideView(vis : Boolean){ visibility = if (vis){ View.GONE } else { View.VISIBLE } } -fun Context.DisplayToast(message: String){ +fun Context.displayToast(message: String){ Toast.makeText(this, message, Toast.LENGTH_LONG).show() } diff --git a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetKotlin.kt b/app/src/main/java/com/appttude/h_mal/easycc/widget/CurrencyAppWidgetKotlin.kt similarity index 95% rename from app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetKotlin.kt rename to app/src/main/java/com/appttude/h_mal/easycc/widget/CurrencyAppWidgetKotlin.kt index 5cf7fed..6215cf8 100644 --- a/app/src/main/java/com/appttude/h_mal/easycc/mvvm/ui/widget/CurrencyAppWidgetKotlin.kt +++ b/app/src/main/java/com/appttude/h_mal/easycc/widget/CurrencyAppWidgetKotlin.kt @@ -1,4 +1,4 @@ -package com.appttude.h_mal.easycc.mvvm.ui.widget +package com.appttude.h_mal.easycc.widget import android.app.PendingIntent import android.appwidget.AppWidgetManager @@ -10,9 +10,9 @@ import android.util.Log import android.widget.RemoteViews import android.widget.Toast import com.appttude.h_mal.easycc.R -import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl -import com.appttude.h_mal.easycc.mvvm.ui.app.MainActivity -import com.appttude.h_mal.easycc.mvvm.utils.transformIntToArray +import com.appttude.h_mal.easycc.data.repository.RepositoryImpl +import com.appttude.h_mal.easycc.ui.main.MainActivity +import com.appttude.h_mal.easycc.utils.transformIntToArray import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 87220f7..b04fe20 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,13 +1,11 @@ + type="com.appttude.h_mal.easycc.ui.main.MainViewModel" /> + tools:context=".ui.main.MainActivity"> @@ -72,15 +70,14 @@ android:layout_height="wrap_content" android:orientation="vertical"> - + diff --git a/app/src/main/res/layout/currency_app_widget_configure.xml b/app/src/main/res/layout/currency_app_widget_configure.xml index ad331f8..f851bc0 100644 --- a/app/src/main/res/layout/currency_app_widget_configure.xml +++ b/app/src/main/res/layout/currency_app_widget_configure.xml @@ -1,14 +1,11 @@ - + type="com.appttude.h_mal.easycc.ui.widget.WidgetViewModel" /> + tools:context=".ui.widget.CurrencyAppWidgetConfigureActivityKotlin"> diff --git a/app/src/main/res/xml/currency_app_widget_info.xml b/app/src/main/res/xml/currency_app_widget_info.xml index 3d0ca83..0cbb4a1 100644 --- a/app/src/main/res/xml/currency_app_widget_info.xml +++ b/app/src/main/res/xml/currency_app_widget_info.xml @@ -1,6 +1,6 @@