- lint checks done

- added service intent

Took 1 hour 7 minutes
This commit is contained in:
2021-06-12 22:50:52 +01:00
parent 33f1738d1e
commit 9160551cb4
35 changed files with 322 additions and 365 deletions

Binary file not shown.

View File

@@ -22,7 +22,7 @@ import org.kodein.di.generic.singleton
class AppClass : Application(), KodeinAware {
// Kodein Dependecy Injection singletons and providers created
// KODEIN DI components declaration
override val kodein by Kodein.lazy {
import(androidXModule(this@AppClass))

View File

@@ -1,6 +1,5 @@
package com.appttude.h_mal.easycc.data.network
import android.util.Log
import org.json.JSONException
import org.json.JSONObject
import retrofit2.Response
@@ -10,7 +9,6 @@ import java.io.IOException
* This abstract class extract objects from Retrofit [Response]
* or throws IOException if object does not exist
*/
private const val TAG = "SafeApiRequest"
abstract class SafeApiRequest {
suspend fun <T : Any> responseUnwrap(
@@ -45,10 +43,6 @@ abstract class SafeApiRequest {
}
print(log)
// Log.e("Api Response Error", log)
//return error message
//if null return error code
return errorMessageString ?: errorCode
}

View File

@@ -11,18 +11,16 @@ import retrofit2.http.GET
import retrofit2.http.Query
/**
* Retrofit2 Network class to create network requests
* Retrofit Network class to currency api calls
*/
interface BackupCurrencyApi {
// Get rate from server with arguments passed in Repository
@GET("latest?")
suspend fun getCurrencyRate(
@Query("from") currencyFrom: String,
@Query("to") currencyTo: String
): Response<CurrencyResponse>
// interface invokation to be used in application class
companion object {
operator fun invoke(
networkConnectionInterceptor: NetworkConnectionInterceptor,
@@ -34,7 +32,6 @@ interface BackupCurrencyApi {
.addNetworkInterceptor(networkConnectionInterceptor)
.build()
// Build retrofit
return Retrofit.Builder()
.client(okkHttpclient)
.baseUrl("https://api.frankfurter.app/")
@@ -44,6 +41,4 @@ interface BackupCurrencyApi {
}
}
}

View File

@@ -12,7 +12,7 @@ import retrofit2.http.GET
import retrofit2.http.Query
/**
* Retrofit2 Network class to create network requests
* Retrofit Network class to currency api calls
*/
interface CurrencyApi {
@@ -28,14 +28,12 @@ interface CurrencyApi {
interceptor: HttpLoggingInterceptor
): CurrencyApi {
// okkHttpclient with injected interceptors
val okkHttpclient = OkHttpClient.Builder()
.addInterceptor(interceptor)
.addInterceptor(queryInterceptor)
.addNetworkInterceptor(networkConnectionInterceptor)
.build()
// Build retrofit
return Retrofit.Builder()
.client(okkHttpclient)
.baseUrl("https://free.currencyconverterapi.com/api/v3/")

View File

@@ -3,14 +3,17 @@ package com.appttude.h_mal.easycc.data.network.interceptors
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
/**
* Interceptor used in [CurrencyApi] to intercept network status
* Interceptor used in network classes to check network status
*
*/
@Suppress("DEPRECATION")
class NetworkConnectionInterceptor(
context: Context
) : Interceptor {
@@ -29,6 +32,7 @@ class NetworkConnectionInterceptor(
val connectivityManager =
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
connectivityManager?.let {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
result = when {
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
@@ -36,6 +40,16 @@ class NetworkConnectionInterceptor(
else -> false
}
}
} else {
it.activeNetworkInfo?.run {
result = when (type) {
ConnectivityManager.TYPE_WIFI -> true
ConnectivityManager.TYPE_MOBILE -> true
ConnectivityManager.TYPE_ETHERNET -> true
else -> false
}
}
}
}
return result
}

View File

@@ -1,7 +1,6 @@
package com.appttude.h_mal.easycc.data.network.interceptors
import android.content.Context
import com.appttude.h_mal.easycc.BuildConfig
import com.appttude.h_mal.easycc.R
import okhttp3.HttpUrl
import okhttp3.Interceptor

View File

@@ -18,8 +18,8 @@ class PreferenceProvider(context: Context) {
private val appContext = context.applicationContext
// Instance of Shared preferences
private val preference: SharedPreferences
= PreferenceManager.getDefaultSharedPreferences(appContext)
private val preference: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(appContext)
// Lazy declaration of default rate if no rate is retrieved from
private val defaultRate: String by lazy {
@@ -50,8 +50,10 @@ class PreferenceProvider(context: Context) {
}
// Save currency pairs for widget
fun saveWidgetConversionPair(fromString: String,
toString: String, appWidgetId: Int) {
fun saveWidgetConversionPair(
fromString: String,
toString: String, appWidgetId: Int
) {
preference.edit()
.putString("${appWidgetId}_$CURRENCY_ONE", fromString)
@@ -68,7 +70,8 @@ class PreferenceProvider(context: Context) {
}
private fun getWidgetConversionString(
appWidgetId: Int, conversionName: String): String? {
appWidgetId: Int, conversionName: String
): String? {
return preference
.getString("${appWidgetId}_$conversionName", defaultRate)
}
@@ -78,7 +81,6 @@ class PreferenceProvider(context: Context) {
.remove("${id}_$CURRENCY_ONE")
.remove("${id}_$CURRENCY_TWO")
.apply()
}
}

View File

@@ -49,8 +49,10 @@ class RepositoryImpl (
override fun getWidgetConversionPairs(appWidgetId: Int): Pair<String?, String?> =
prefs.getWidgetConversionPair(appWidgetId)
override fun setWidgetConversionPairs(fromCurrency: String,
toCurrency: String, appWidgetId: Int) {
override fun setWidgetConversionPairs(
fromCurrency: String,
toCurrency: String, appWidgetId: Int
) {
return prefs.saveWidgetConversionPair(fromCurrency, toCurrency, appWidgetId)
}

View File

@@ -2,7 +2,6 @@ package com.appttude.h_mal.easycc.helper
import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.models.CurrencyModelInterface
import java.lang.Exception
class CurrencyDataHelper(
val repository: Repository

View File

@@ -4,10 +4,8 @@ import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.models.CurrencyModel
import com.appttude.h_mal.easycc.utils.trimToThree
import kotlin.Exception
class WidgetHelper(
val helper: CurrencyDataHelper,
private val helper: CurrencyDataHelper,
val repository: Repository
) {

View File

@@ -13,6 +13,7 @@ import kotlinx.android.synthetic.main.custom_dialog.*
/**
* Custom dialog when selecting currencies from list with filter
*/
@Suppress("DEPRECATION")
class CustomDialogClass(
context: Context,
private val clickListener: ClickListener
@@ -31,7 +32,8 @@ class CustomDialogClass(
val arrayAdapter =
ArrayAdapter.createFromResource(
context, R.array.currency_arrays,
android.R.layout.simple_list_item_1)
android.R.layout.simple_list_item_1
)
list_view.adapter = arrayAdapter
@@ -41,6 +43,7 @@ class CustomDialogClass(
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
arrayAdapter.filter.filter(charSequence)
}
override fun afterTextChanged(editable: Editable) {}
})

View File

@@ -20,6 +20,7 @@ import org.kodein.di.KodeinAware
import org.kodein.di.android.kodein
import org.kodein.di.generic.instance
@Suppress("DEPRECATION")
class MainActivity : AppCompatActivity(), KodeinAware, View.OnClickListener {
// Retrieve MainViewModelFactory via dependency injection
@@ -54,10 +55,10 @@ class MainActivity : AppCompatActivity(), KodeinAware, View.OnClickListener {
}
private fun setUpObservers() {
viewModel.operationStartedListener.observe(this, Observer {
viewModel.operationStartedListener.observe(this, {
progressBar.hideView(false)
})
viewModel.operationFinishedListener.observe(this, Observer { pair ->
viewModel.operationFinishedListener.observe(this, { pair ->
// hide progress bar
progressBar.hideView(true)
if (pair.first) {

View File

@@ -98,7 +98,9 @@ class MainViewModel(
when (tag.toString()) {
"top" -> rateIdFrom = currencyName
"bottom" -> rateIdTo = currencyName
else -> { return }
else -> {
return
}
}
getExchangeRate()

View File

@@ -25,7 +25,8 @@ import org.kodein.di.generic.instance
/**
* The configuration screen for the [CurrencyAppWidgetKotlin] AppWidget.
*/
class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAware, View.OnClickListener {
class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAware,
View.OnClickListener {
override val kodein by kodein()
private val factory: WidgetViewModelFactory by instance()
@@ -47,7 +48,8 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
val extras = intent.extras
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
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.
@@ -72,7 +74,7 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
}
private fun setupObserver() {
viewModel.operationFinishedListener.observe(this, Observer {
viewModel.operationFinishedListener.observe(this, {
// it.first is a the success of the operation
if (it.first) {
@@ -136,7 +138,8 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
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,
Intent(
this@CurrencyAppWidgetConfigureActivityKotlin,
CurrencyAppWidgetKotlin::class.java
).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE

View File

@@ -1,48 +0,0 @@
package com.appttude.h_mal.easycc.ui.widget
import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.WindowManager
import android.widget.ArrayAdapter
import com.appttude.h_mal.easycc.R
import kotlinx.android.synthetic.main.custom_dialog.*
/*
widget for when submitting the completed selections
*/
class WidgetItemSelectDialog(
context: Context,
private val dialogResult: DialogResult
) :Dialog(context){
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.custom_dialog)
window!!.setBackgroundDrawableResource(android.R.color.transparent)
window!!.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
val arrayAdapter = ArrayAdapter.createFromResource(context, R.array.currency_arrays, android.R.layout.simple_list_item_1)
list_view.adapter = 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) {
arrayAdapter.filter.filter(charSequence)
}
override fun afterTextChanged(editable: Editable) {}
})
list_view.setOnItemClickListener{ adapterView, _, i, _ ->
dialogResult.result(adapterView.getItemAtPosition(i).toString())
dismiss()
}
}
}
interface DialogResult{
fun result(result : String)
}

View File

@@ -23,8 +23,7 @@ class WidgetViewModel(
// Set default values for text views
fun initiate(appId: Int) {
appWidgetId = appId
val widgetString
= repository.getWidgetConversionPairs(appId)
val widgetString = repository.getWidgetConversionPairs(appId)
rateIdFrom = widgetString.first ?: defaultCurrency
rateIdTo = widgetString.second ?: defaultCurrency
@@ -61,7 +60,9 @@ class WidgetViewModel(
when (tag.toString()) {
"top" -> rateIdFrom = currencyName
"bottom" -> rateIdTo = currencyName
else -> { return }
else -> {
return
}
}
}

View File

@@ -2,7 +2,6 @@ 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)

View File

@@ -10,7 +10,11 @@ fun EditText.clearEditText(){
}
fun View.hideView(vis: Boolean) {
visibility = if (vis){ View.GONE } else { View.VISIBLE }
visibility = if (vis) {
View.GONE
} else {
View.VISIBLE
}
}
fun Context.displayToast(message: String) {

View File

@@ -1,21 +1,11 @@
package com.appttude.h_mal.easycc.widget
import android.app.Activity
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.RemoteViews
import com.appttude.h_mal.easycc.R
import com.appttude.h_mal.easycc.helper.WidgetHelper
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
import com.appttude.h_mal.easycc.widget.WidgetServiceIntent.Companion.enqueueWork
import org.kodein.di.KodeinAware
import org.kodein.di.LateInitKodein
import org.kodein.di.generic.instance
@@ -23,9 +13,8 @@ import org.kodein.di.generic.instance
/**
* Implementation of App Widget functionality.
* App Widget Configuration implemented in [CurrencyAppWidgetConfigureActivityKotlin]
* App Widget Configuration implemented in [CurrencyAppWidgetKotlin]
*/
private const val TAG = "CurrencyAppWidgetKotlin"
class CurrencyAppWidgetKotlin : AppWidgetProvider() {
@@ -39,12 +28,7 @@ class CurrencyAppWidgetKotlin : AppWidgetProvider() {
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
Log.i(TAG, "onUpdate() appWidgetIds = ${appWidgetIds.size}")
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
loadWidget(context)
super.onUpdate(context, appWidgetManager, appWidgetIds)
}
@@ -58,113 +42,13 @@ class CurrencyAppWidgetKotlin : AppWidgetProvider() {
}
override fun onEnabled(context: Context) {
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
// Enter relevant functionality for when the first widget is created
AppWidgetManager.getInstance(context).apply {
val thisAppWidget =
ComponentName(context.packageName, CurrencyAppWidgetKotlin::class.java.name)
val appWidgetIds = getAppWidgetIds(thisAppWidget)
onUpdate(context, this, appWidgetIds)
}
loadWidget(context)
super.onEnabled(context)
}
override fun onDisabled(context: Context) {
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
// Enter relevant functionality for when the last widget is disabled
}
private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.currency_app_widget)
CoroutineScope(Dispatchers.Main).launch {
val exchangeResponse = repository.getWidgetData()
exchangeResponse?.let {
val titleString = "${it.from}${it.to}"
views.setTextViewText(R.id.exchangeName, titleString)
views.setTextViewText(R.id.exchangeRate, it.rate.toString())
setUpdateIntent(context, appWidgetId).let { intent ->
//set the pending intent to the icon
views.setImageViewResource(R.id.refresh_icon, R.drawable.ic_refresh_white_24dp)
views.setOnClickPendingIntent(R.id.refresh_icon, intent)
}
val clickIntentTemplate = clickingIntent(context)
val configPendingIntent =
PendingIntent.getActivity(
context, appWidgetId, 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 fun setUpdateIntent(context: Context, appWidgetId: Int): PendingIntent? {
//Create update intent for refresh icon
val updateIntent = Intent(
context, CurrencyAppWidgetKotlin::class.java
).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, transformIntToArray(appWidgetId))
}
//add previous intent to this pending intent
return PendingIntent.getBroadcast(
context,
appWidgetId,
updateIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
private fun clickingIntent(
context: Context
): Intent {
val pair = repository.repository.getConversionPair()
val s1 = pair.first
val s2 = pair.second
return Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
putExtra("parse_1", s1)
putExtra("parse_2", s2)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
}
private fun <T: Activity> clickingIntent(
context: Context,
activity: Class<T>,
vararg argPairs: Pair<String, Any?>
): Intent {
return Intent(context, activity::class.java).apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
argPairs.forEach {
putExtra(it.first, it.second)
}
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
}
private fun <T: Any> Intent.putExtra(s: String, second: T?) {
when(second){
is String -> putExtra(s,second)
}
private fun loadWidget(context: Context) {
val mIntent = Intent(context, CurrencyAppWidgetKotlin::class.java)
enqueueWork(context, mIntent)
}
}

View File

@@ -0,0 +1,121 @@
package com.appttude.h_mal.easycc.widget
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.widget.RemoteViews
import androidx.core.app.JobIntentService
import com.appttude.h_mal.easycc.R
import com.appttude.h_mal.easycc.helper.WidgetHelper
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
import org.kodein.di.LateInitKodein
import org.kodein.di.generic.instance
class WidgetServiceIntent : JobIntentService() {
//DI with kodein to use in CurrencyAppWidgetKotlin
private val kodein = LateInitKodein()
private val repository: WidgetHelper by kodein.instance()
override fun onHandleWork(intent: Intent) {
kodein.baseKodein = this.kodein
val appWidgetManager = AppWidgetManager.getInstance(this)
val thisAppWidget = ComponentName(packageName, CurrencyAppWidgetKotlin::class.java.name)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
for (appWidgetId in appWidgetIds) {
updateAppWidget(this, appWidgetManager, appWidgetId)
}
}
private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.currency_app_widget)
CoroutineScope(Dispatchers.Main).launch {
val exchangeResponse = repository.getWidgetData()
exchangeResponse?.let {
val titleString = "${it.from}${it.to}"
views.setTextViewText(R.id.exchangeName, titleString)
views.setTextViewText(R.id.exchangeRate, it.rate.toString())
setUpdateIntent(context, appWidgetId).let { intent ->
//set the pending intent to the icon
views.setImageViewResource(R.id.refresh_icon, R.drawable.ic_refresh_white_24dp)
views.setOnClickPendingIntent(R.id.refresh_icon, intent)
}
val clickIntentTemplate = clickingIntent(context)
val configPendingIntent =
PendingIntent.getActivity(
context, appWidgetId, 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 fun setUpdateIntent(context: Context, appWidgetId: Int): PendingIntent? {
//Create update intent for refresh icon
val updateIntent = Intent(
context, CurrencyAppWidgetKotlin::class.java
).apply {
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, transformIntToArray(appWidgetId))
}
//add previous intent to this pending intent
return PendingIntent.getBroadcast(
context,
appWidgetId,
updateIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
private fun clickingIntent(
context: Context
): Intent {
val pair = repository.repository.getConversionPair()
val s1 = pair.first
val s2 = pair.second
return Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
putExtra("parse_1", s1)
putExtra("parse_2", s2)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
}
companion object {
/**
* Unique job ID for this service.
*/
private const val JOB_ID = 1000
/**
* Convenience method for enqueuing work in to this service.
*/
fun enqueueWork(context: Context, work: Intent) {
enqueueWork(context, WidgetServiceIntent::class.java, JOB_ID, work)
}
}
}

View File

@@ -1,20 +0,0 @@
package com.appttude.h_mal.easycc;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View File

@@ -2,7 +2,6 @@ package com.appttude.h_mal.easycc.repository
import com.appttude.h_mal.easycc.data.network.api.BackupCurrencyApi
import com.appttude.h_mal.easycc.data.network.api.CurrencyApi
import com.appttude.h_mal.easycc.data.network.response.CurrencyResponse
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.data.repository.Repository
@@ -29,8 +28,10 @@ class RepositoryNetworkTest{
@Mock
lateinit var api: CurrencyApi
@Mock
lateinit var apiBackup: BackupCurrencyApi
@Mock
lateinit var prefs: PreferenceProvider

View File

@@ -1,6 +1,5 @@
package com.appttude.h_mal.easycc.repository
import android.content.Context
import com.appttude.h_mal.easycc.data.network.api.BackupCurrencyApi
import com.appttude.h_mal.easycc.data.network.api.CurrencyApi
import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider
@@ -19,8 +18,10 @@ class RepositoryStorageTest {
@Mock
lateinit var api: CurrencyApi
@Mock
lateinit var apiBackup: BackupCurrencyApi
@Mock
lateinit var prefs: PreferenceProvider

View File

@@ -6,10 +6,10 @@ import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.appttude.h_mal.easycc.data.network.response.ResponseObject
import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.helper.CurrencyDataHelper
import kotlinx.coroutines.runBlocking
import org.junit.Before
import com.appttude.h_mal.easycc.utils.observeOnce
import kotlinx.coroutines.runBlocking
import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
@@ -48,7 +48,8 @@ class MainViewModelTest {
//WHEN
Mockito.`when`(bundle.getString("parse_1")).thenReturn(currencyOne)
Mockito.`when`(bundle.getString("parse_2")).thenReturn(currencyTwo)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
//THEN
viewModel.initiate(bundle)
@@ -71,7 +72,8 @@ class MainViewModelTest {
//WHEN
Mockito.`when`(repository.getConversionPair()).thenReturn(pair)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
//THEN
viewModel.initiate(null)
@@ -128,7 +130,6 @@ class MainViewModelTest {
}
@Test
fun setCurrencyName_validValues_successResponse() = runBlocking {
//GIVEN
@@ -139,7 +140,8 @@ class MainViewModelTest {
val responseObject = mock(ResponseObject::class.java)
//WHEN
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
//THEN
viewModel.setCurrencyName(tag, currencyOne)
@@ -163,7 +165,8 @@ class MainViewModelTest {
val responseObject = mock(ResponseObject::class.java)
//WHEN
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
//THEN
viewModel.setCurrencyName(tag, currencyOne)
@@ -185,7 +188,8 @@ class MainViewModelTest {
val responseObject = mock(ResponseObject::class.java)
//WHEN
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
//THEN
viewModel.setCurrencyName(tag, currencyOne)

View File

@@ -3,8 +3,8 @@ package com.appttude.h_mal.easycc.ui.widget
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.utils.observeOnce
import org.junit.Before
import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
@@ -14,6 +14,7 @@ import org.mockito.MockitoAnnotations
private const val currencyOne = "AUD - Australian Dollar"
private const val currencyTwo = "GBP - British Pound"
class WidgetViewModelTest {
// Run tasks synchronously

View File

@@ -1,4 +1,4 @@
package com.appttude.h_mal.easycc
package com.appttude.h_mal.easycc.utils
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner

View File

@@ -1,7 +1,6 @@
package com.appttude.h_mal.easycc.utils
import androidx.lifecycle.LiveData
import com.appttude.h_mal.easycc.OneTimeObserver
fun <T> LiveData<T>.observeOnce(onChangeHandler: (T) -> Unit) {
val observer = OneTimeObserver(handler = onChangeHandler)

View File

@@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.61'
ext.kotlin_version = '1.4.10'
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.android.tools.build:gradle:4.0.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@@ -1,6 +1,6 @@
#Thu Mar 05 18:27:33 UTC 2020
#Sat Jun 12 22:27:25 BST 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip