mirror of
https://github.com/hmalik144/EasyCC_Master.git
synced 2026-03-17 23:16:09 +00:00
Unit tests added
Query interceptor added Unit tests created - Repository test network - Repository test storage
This commit is contained in:
@@ -2,8 +2,8 @@ package com.appttude.h_mal.easycc.mvvm.application
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl
|
import com.appttude.h_mal.easycc.mvvm.data.repository.RepositoryImpl
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.network.NetworkConnectionInterceptor
|
import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.NetworkConnectionInterceptor
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.network.QueryInterceptor
|
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.network.api.CurrencyApi
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.prefs.PreferenceProvider
|
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.app.MainViewModelFactory
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.appttude.h_mal.easycc.mvvm.data.network.api
|
package com.appttude.h_mal.easycc.mvvm.data.network.api
|
||||||
|
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.network.response.ResponseObject
|
import com.appttude.h_mal.easycc.mvvm.data.network.response.ResponseObject
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.network.NetworkConnectionInterceptor
|
import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.NetworkConnectionInterceptor
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.network.QueryInterceptor
|
import com.appttude.h_mal.easycc.mvvm.data.network.interceptors.QueryInterceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.easycc.mvvm.data.network
|
package com.appttude.h_mal.easycc.mvvm.data.network.interceptors
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
@@ -7,6 +7,10 @@ import okhttp3.Interceptor
|
|||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interceptor used in [CurrencyApi] to intercept network status
|
||||||
|
*
|
||||||
|
*/
|
||||||
class NetworkConnectionInterceptor(
|
class NetworkConnectionInterceptor(
|
||||||
context: Context
|
context: Context
|
||||||
) : Interceptor {
|
) : Interceptor {
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
package com.appttude.h_mal.easycc.mvvm.data.network
|
package com.appttude.h_mal.easycc.mvvm.data.network.interceptors
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
|
import com.appttude.h_mal.easycc.BuildConfig
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interceptor used in CurrencyApi
|
||||||
|
* Adds apiKey to query parameters
|
||||||
|
*/
|
||||||
class QueryInterceptor() : Interceptor {
|
class QueryInterceptor() : Interceptor {
|
||||||
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
@@ -16,7 +20,7 @@ class QueryInterceptor() : Interceptor {
|
|||||||
val originalHttpUrl: HttpUrl = original.url()
|
val originalHttpUrl: HttpUrl = original.url()
|
||||||
|
|
||||||
val url = originalHttpUrl.newBuilder()
|
val url = originalHttpUrl.newBuilder()
|
||||||
.addQueryParameter("apikey", "a4f93cc2ff05dd772321")
|
.addQueryParameter("apikey", BuildConfig.CC_API_KEY)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// Add amended Url back to request
|
// Add amended Url back to request
|
||||||
@@ -5,76 +5,80 @@ import android.content.SharedPreferences
|
|||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.appttude.h_mal.easycc.R
|
import com.appttude.h_mal.easycc.R
|
||||||
|
|
||||||
private const val CONVERSION_ONE = "conversion_one"
|
/**
|
||||||
private const val CONVERSION_TWO = "conversion_two"
|
* Shared prefs class used for storing conversion name values as pairs
|
||||||
private const val CONVERSION_ONE_WIDGET = "conversion_one_widget"
|
* Then retrieving as pairs
|
||||||
private const val CONVERSION_TWO_WIDGET = "conversion_two_widget"
|
*
|
||||||
|
*/
|
||||||
|
private const val CURRENCY_ONE = "conversion_one"
|
||||||
|
private const val CURRENCY_TWO = "conversion_two"
|
||||||
|
|
||||||
class PreferenceProvider(
|
class PreferenceProvider(context: Context) {
|
||||||
context: Context
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val appContext = context.applicationContext
|
private val appContext = context.applicationContext
|
||||||
|
|
||||||
|
// Instance of Shared preferences
|
||||||
private val preference: SharedPreferences
|
private val preference: SharedPreferences
|
||||||
get() = PreferenceManager.getDefaultSharedPreferences(appContext)
|
= PreferenceManager.getDefaultSharedPreferences(appContext)
|
||||||
|
|
||||||
private val defaultRate: String = context.resources.getStringArray(R.array.currency_arrays)[0]
|
|
||||||
|
|
||||||
|
// Lazy declaration of default rate if no rate is retrieved from
|
||||||
|
private val defaultRate: String by lazy {
|
||||||
|
context.resources.getStringArray(R.array.currency_arrays)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save currency pairs into prefs
|
||||||
fun saveConversionPair(s1: String, s2: String) {
|
fun saveConversionPair(s1: String, s2: String) {
|
||||||
preference.edit().putString(
|
preference.edit()
|
||||||
CONVERSION_ONE,
|
.putString(CURRENCY_ONE, s1)
|
||||||
s1
|
.putString(CURRENCY_TWO, s2)
|
||||||
).putString(
|
.apply()
|
||||||
CONVERSION_TWO,
|
|
||||||
s2
|
|
||||||
).apply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve Currency pairs from prefs
|
||||||
|
// Returns Pairs
|
||||||
fun getConversionPair(): Pair<String?, String?> {
|
fun getConversionPair(): Pair<String?, String?> {
|
||||||
val s1 = getLastConversionOne()
|
val fromString = getConversionString(CURRENCY_ONE)
|
||||||
val s2 = getLastConversionTwo()
|
val toString = getConversionString(CURRENCY_TWO)
|
||||||
|
|
||||||
return Pair(s1,s2)
|
return Pair(fromString, toString)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLastConversionOne(): String? {
|
|
||||||
return preference.getString(CONVERSION_ONE, defaultRate)
|
private fun getConversionString(conversionName: String): String? {
|
||||||
|
return preference
|
||||||
|
.getString(conversionName, defaultRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLastConversionTwo(): String? {
|
// Save currency pairs for widget
|
||||||
return preference.getString(CONVERSION_TWO, defaultRate)
|
fun saveWidgetConversionPair(fromString: String,
|
||||||
|
toString: String, appWidgetId: Int) {
|
||||||
|
|
||||||
|
preference.edit()
|
||||||
|
.putString("${appWidgetId}_$CURRENCY_ONE", fromString)
|
||||||
|
.putString("${appWidgetId}_$CURRENCY_TWO", toString)
|
||||||
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveWidgetConversionPair(s1: String, s2: String, id: Int) {
|
// Retrieve currency pairs for widget
|
||||||
preference.edit().putString(
|
fun getWidgetConversionPair(appWidgetId: Int): Pair<String?, String?> {
|
||||||
"${id}_$CONVERSION_ONE",
|
val fromString = getWidgetConversionString(appWidgetId, CURRENCY_ONE)
|
||||||
s1
|
val toString = getWidgetConversionString(appWidgetId, CURRENCY_TWO)
|
||||||
).putString(
|
|
||||||
"${id}_$CONVERSION_TWO",
|
return Pair(fromString, toString)
|
||||||
s2
|
|
||||||
).apply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWidgetConversionPair(id: Int): Pair<String?, String?> {
|
private fun getWidgetConversionString(
|
||||||
val s1 = getWidgetLastConversionOne(id)
|
appWidgetId: Int, conversionName: String): String? {
|
||||||
val s2 = getWidgetLastConversionTwo(id)
|
return preference
|
||||||
|
.getString("${appWidgetId}_$conversionName", defaultRate)
|
||||||
return Pair(s1, s2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getWidgetLastConversionOne(id: Int): String? {
|
fun removeWidgetConversion(id: Int) {
|
||||||
return preference.getString("${id}_$CONVERSION_ONE", defaultRate)
|
preference.edit()
|
||||||
}
|
.remove("${id}_$CURRENCY_ONE")
|
||||||
|
.remove("${id}_$CURRENCY_TWO")
|
||||||
|
.apply()
|
||||||
|
|
||||||
private fun getWidgetLastConversionTwo(id: Int): String? {
|
|
||||||
return preference.getString("${id}_$CONVERSION_TWO", defaultRate)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeWidgetConversion(id: Int){
|
|
||||||
preference.edit().remove("${id}_$CONVERSION_ONE").apply()
|
|
||||||
preference.edit().remove("${id}_$CONVERSION_TWO").apply()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
package com.appttude.h_mal.easycc.mvvm.data.repository
|
package com.appttude.h_mal.easycc.mvvm.data.repository
|
||||||
|
|
||||||
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.response.ResponseObject
|
||||||
import com.appttude.h_mal.easycc.mvvm.utils.convertPairsListToString
|
|
||||||
|
/**
|
||||||
|
* Main entry point for accessing currency data.
|
||||||
|
*/
|
||||||
|
|
||||||
interface Repository {
|
interface Repository {
|
||||||
|
|
||||||
suspend fun getData(s1: String, s2: String): ResponseObject
|
suspend fun getData(fromCurrency: String, toCurrency: String): ResponseObject
|
||||||
|
|
||||||
fun getConversionPair(): Pair<String?, String?>
|
fun getConversionPair(): Pair<String?, String?>
|
||||||
|
|
||||||
fun setConversionPair(s1: String, s2: String)
|
fun setConversionPair(fromCurrency: String, toCurrency: String)
|
||||||
|
|
||||||
fun getArrayList(): Array<String>
|
fun getArrayList(): Array<String>
|
||||||
|
|
||||||
fun getWidgetConversionPairs(id: Int): Pair<String?, String?>
|
fun getWidgetConversionPairs(appWidgetId: Int): Pair<String?, String?>
|
||||||
|
|
||||||
fun setWidgetConversionPairs(s1: String, s2: String, id: Int)
|
fun setWidgetConversionPairs(fromCurrency: String, toCurrency: String, appWidgetId: Int)
|
||||||
|
|
||||||
fun removeWidgetConversionPairs(id: Int)
|
fun removeWidgetConversionPairs(id: Int)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.appttude.h_mal.easycc.mvvm.data.repository
|
package com.appttude.h_mal.easycc.mvvm.data.repository
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.appttude.h_mal.easycc.BuildConfig
|
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.prefs.PreferenceProvider
|
import com.appttude.h_mal.easycc.mvvm.data.prefs.PreferenceProvider
|
||||||
import com.appttude.h_mal.easycc.R
|
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.response.ResponseObject
|
||||||
@@ -9,7 +8,9 @@ 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.data.network.api.CurrencyApi
|
||||||
import com.appttude.h_mal.easycc.mvvm.utils.convertPairsListToString
|
import com.appttude.h_mal.easycc.mvvm.utils.convertPairsListToString
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation of [Repository]. Single entry point for managing currency' data.
|
||||||
|
*/
|
||||||
class RepositoryImpl (
|
class RepositoryImpl (
|
||||||
private val api: CurrencyApi,
|
private val api: CurrencyApi,
|
||||||
private val prefs: PreferenceProvider,
|
private val prefs: PreferenceProvider,
|
||||||
@@ -18,29 +19,31 @@ class RepositoryImpl (
|
|||||||
|
|
||||||
private val appContext = context.applicationContext
|
private val appContext = context.applicationContext
|
||||||
|
|
||||||
override suspend fun getData(s1: String, s2: String
|
override suspend fun getData(fromCurrency: String, toCurrency: String
|
||||||
): ResponseObject{
|
): ResponseObject{
|
||||||
val currencyPair = convertPairsListToString(s1, s2)
|
// Set currency pairs as correct string for api query eg. AUD_GBP
|
||||||
return responseUnwrap{
|
val currencyPair = convertPairsListToString(fromCurrency, toCurrency)
|
||||||
api.getCurrencyRate(currencyPair)}
|
return responseUnwrap{ api.getCurrencyRate(currencyPair)}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getConversionPair(): Pair<String?, String?> {
|
override fun getConversionPair(): Pair<String?, String?> {
|
||||||
return prefs.getConversionPair()
|
return prefs.getConversionPair()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setConversionPair(s1: String, s2: String){
|
override fun setConversionPair(fromCurrency: String, toCurrency: String){
|
||||||
prefs.saveConversionPair(s1, s2)
|
prefs.saveConversionPair(fromCurrency, toCurrency)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getArrayList(): Array<String> =
|
override fun getArrayList(): Array<String> =
|
||||||
appContext.resources.getStringArray(R.array.currency_arrays)
|
appContext.resources.getStringArray(R.array.currency_arrays)
|
||||||
|
|
||||||
override fun getWidgetConversionPairs(id: Int): Pair<String?, String?> =
|
override fun getWidgetConversionPairs(appWidgetId: Int): Pair<String?, String?> =
|
||||||
prefs.getWidgetConversionPair(id)
|
prefs.getWidgetConversionPair(appWidgetId)
|
||||||
|
|
||||||
override fun setWidgetConversionPairs(s1: String, s2: String, id: Int) =
|
override fun setWidgetConversionPairs(fromCurrency: String,
|
||||||
prefs.saveWidgetConversionPair(s1, s2, id)
|
toCurrency: String, appWidgetId: Int) {
|
||||||
|
return prefs.saveWidgetConversionPair(fromCurrency, toCurrency, appWidgetId)
|
||||||
|
}
|
||||||
|
|
||||||
override fun removeWidgetConversionPairs(id: Int) =
|
override fun removeWidgetConversionPairs(id: Int) =
|
||||||
prefs.removeWidgetConversion(id)
|
prefs.removeWidgetConversion(id)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.widget.EditText
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.appttude.h_mal.easycc.mvvm.data.repository.Repository
|
import com.appttude.h_mal.easycc.mvvm.data.repository.Repository
|
||||||
|
import com.appttude.h_mal.easycc.mvvm.utils.toTwoDp
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -26,9 +27,7 @@ class MainViewModel(
|
|||||||
var rateListener: RateListener? = null
|
var rateListener: RateListener? = null
|
||||||
|
|
||||||
//operation results livedata based on outcome of operation
|
//operation results livedata based on outcome of operation
|
||||||
val operationSuccess = MutableLiveData<Boolean>()
|
val operationSuccess = MutableLiveData<Pair<Boolean, String>>()
|
||||||
val operationFailed = MutableLiveData<String>()
|
|
||||||
|
|
||||||
val currencyRate = MutableLiveData<Double>()
|
val currencyRate = MutableLiveData<Double>()
|
||||||
|
|
||||||
private var conversionRate: Double = 0.00
|
private var conversionRate: Double = 0.00
|
||||||
@@ -71,11 +70,6 @@ class MainViewModel(
|
|||||||
editText.setText(newTopVal.toBigDecimal().toPlainString())
|
editText.setText(newTopVal.toBigDecimal().toPlainString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Double.toTwoDp() = run {
|
|
||||||
val df = DecimalFormat("#.##")
|
|
||||||
java.lang.Double.valueOf(df.format(this))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun start(){
|
fun start(){
|
||||||
if (rateIdFrom != rateIdTo){
|
if (rateIdFrom != rateIdTo){
|
||||||
getExchangeRate()
|
getExchangeRate()
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.appttude.h_mal.easycc.mvvm.utils
|
package com.appttude.h_mal.easycc.mvvm.utils
|
||||||
|
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
|
||||||
fun transformIntToArray(int: Int): IntArray{
|
fun transformIntToArray(int: Int): IntArray{
|
||||||
return intArrayOf(int)
|
return intArrayOf(int)
|
||||||
}
|
}
|
||||||
@@ -12,4 +14,9 @@ fun String.trimToThree(): String{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun convertPairsListToString(s1: String, s2: String): String =
|
fun convertPairsListToString(s1: String, s2: String): String =
|
||||||
"${s1.trimToThree()}_${s2.trimToThree()}"
|
"${s1.trimToThree()}_${s2.trimToThree()}"
|
||||||
|
|
||||||
|
fun Double.toTwoDp() = run {
|
||||||
|
val df = DecimalFormat("#.##")
|
||||||
|
java.lang.Double.valueOf(df.format(this))
|
||||||
|
}
|
||||||
@@ -45,7 +45,7 @@ class RepositoryStorageTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun saveAndRetrieveCredentials_PositiveResponse() {
|
fun saveAndRetrieveWidgetPairs_PositiveResponse() {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val s1 = "AUD - Australian Dollar"
|
val s1 = "AUD - Australian Dollar"
|
||||||
val s2 = "GBP - British Pound"
|
val s2 = "GBP - British Pound"
|
||||||
|
|||||||
Reference in New Issue
Block a user