mirror of
https://github.com/hmalik144/EasyCC_Master.git
synced 2026-01-31 02:41:47 +00:00
- lint checks done
- added service intent Took 1 hour 7 minutes
This commit is contained in:
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
@@ -22,7 +22,7 @@ import org.kodein.di.generic.singleton
|
|||||||
|
|
||||||
class AppClass : Application(), KodeinAware {
|
class AppClass : Application(), KodeinAware {
|
||||||
|
|
||||||
// Kodein Dependecy Injection singletons and providers created
|
// KODEIN DI components declaration
|
||||||
override val kodein by Kodein.lazy {
|
override val kodein by Kodein.lazy {
|
||||||
import(androidXModule(this@AppClass))
|
import(androidXModule(this@AppClass))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.appttude.h_mal.easycc.data.network
|
package com.appttude.h_mal.easycc.data.network
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
@@ -10,11 +9,10 @@ import java.io.IOException
|
|||||||
* This abstract class extract objects from Retrofit [Response]
|
* This abstract class extract objects from Retrofit [Response]
|
||||||
* or throws IOException if object does not exist
|
* or throws IOException if object does not exist
|
||||||
*/
|
*/
|
||||||
private const val TAG = "SafeApiRequest"
|
|
||||||
abstract class SafeApiRequest {
|
abstract class SafeApiRequest {
|
||||||
|
|
||||||
suspend fun <T : Any> responseUnwrap(
|
suspend fun <T : Any> responseUnwrap(
|
||||||
call: suspend () -> Response<T>
|
call: suspend () -> Response<T>
|
||||||
): T {
|
): T {
|
||||||
val response = call.invoke()
|
val response = call.invoke()
|
||||||
|
|
||||||
@@ -34,21 +32,17 @@ abstract class SafeApiRequest {
|
|||||||
val errorMessageString = errorBody.getError()
|
val errorMessageString = errorBody.getError()
|
||||||
|
|
||||||
//build a log message to log in console
|
//build a log message to log in console
|
||||||
val log = if (errorMessageString.isNullOrEmpty()){
|
val log = if (errorMessageString.isNullOrEmpty()) {
|
||||||
errorCode
|
errorCode
|
||||||
}else{
|
} else {
|
||||||
StringBuilder()
|
StringBuilder()
|
||||||
.append(errorCode)
|
.append(errorCode)
|
||||||
.append("\n")
|
.append("\n")
|
||||||
.append(errorMessageString)
|
.append(errorMessageString)
|
||||||
.toString()
|
.toString()
|
||||||
}
|
}
|
||||||
print(log)
|
print(log)
|
||||||
|
|
||||||
// Log.e("Api Response Error", log)
|
|
||||||
|
|
||||||
//return error message
|
|
||||||
//if null return error code
|
|
||||||
return errorMessageString ?: errorCode
|
return errorMessageString ?: errorCode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,39 +11,34 @@ import retrofit2.http.GET
|
|||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrofit2 Network class to create network requests
|
* Retrofit Network class to currency api calls
|
||||||
*/
|
*/
|
||||||
interface BackupCurrencyApi {
|
interface BackupCurrencyApi {
|
||||||
|
|
||||||
// Get rate from server with arguments passed in Repository
|
|
||||||
@GET("latest?")
|
@GET("latest?")
|
||||||
suspend fun getCurrencyRate(
|
suspend fun getCurrencyRate(
|
||||||
@Query("from") currencyFrom: String,
|
@Query("from") currencyFrom: String,
|
||||||
@Query("to") currencyTo: String
|
@Query("to") currencyTo: String
|
||||||
): Response<CurrencyResponse>
|
): Response<CurrencyResponse>
|
||||||
|
|
||||||
// interface invokation to be used in application class
|
companion object {
|
||||||
companion object{
|
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||||
interceptor: HttpLoggingInterceptor
|
interceptor: HttpLoggingInterceptor
|
||||||
) : BackupCurrencyApi{
|
): BackupCurrencyApi {
|
||||||
|
|
||||||
val okkHttpclient = OkHttpClient.Builder()
|
val okkHttpclient = OkHttpClient.Builder()
|
||||||
.addInterceptor(interceptor)
|
.addInterceptor(interceptor)
|
||||||
.addNetworkInterceptor(networkConnectionInterceptor)
|
.addNetworkInterceptor(networkConnectionInterceptor)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// Build retrofit
|
|
||||||
return Retrofit.Builder()
|
return Retrofit.Builder()
|
||||||
.client(okkHttpclient)
|
.client(okkHttpclient)
|
||||||
.baseUrl("https://api.frankfurter.app/")
|
.baseUrl("https://api.frankfurter.app/")
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build()
|
.build()
|
||||||
.create(BackupCurrencyApi::class.java)
|
.create(BackupCurrencyApi::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,7 @@ import retrofit2.http.GET
|
|||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrofit2 Network class to create network requests
|
* Retrofit Network class to currency api calls
|
||||||
*/
|
*/
|
||||||
interface CurrencyApi {
|
interface CurrencyApi {
|
||||||
|
|
||||||
@@ -21,21 +21,19 @@ interface CurrencyApi {
|
|||||||
suspend fun getCurrencyRate(@Query("q") currency: String): Response<ResponseObject>
|
suspend fun getCurrencyRate(@Query("q") currency: String): Response<ResponseObject>
|
||||||
|
|
||||||
// interface invokation to be used in application class
|
// interface invokation to be used in application class
|
||||||
companion object{
|
companion object {
|
||||||
operator fun invoke(
|
operator fun invoke(
|
||||||
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||||
queryInterceptor: QueryInterceptor,
|
queryInterceptor: QueryInterceptor,
|
||||||
interceptor: HttpLoggingInterceptor
|
interceptor: HttpLoggingInterceptor
|
||||||
) : CurrencyApi{
|
): CurrencyApi {
|
||||||
|
|
||||||
// okkHttpclient with injected interceptors
|
|
||||||
val okkHttpclient = OkHttpClient.Builder()
|
val okkHttpclient = OkHttpClient.Builder()
|
||||||
.addInterceptor(interceptor)
|
.addInterceptor(interceptor)
|
||||||
.addInterceptor(queryInterceptor)
|
.addInterceptor(queryInterceptor)
|
||||||
.addNetworkInterceptor(networkConnectionInterceptor)
|
.addNetworkInterceptor(networkConnectionInterceptor)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
// Build retrofit
|
|
||||||
return Retrofit.Builder()
|
return Retrofit.Builder()
|
||||||
.client(okkHttpclient)
|
.client(okkHttpclient)
|
||||||
.baseUrl("https://free.currencyconverterapi.com/api/v3/")
|
.baseUrl("https://free.currencyconverterapi.com/api/v3/")
|
||||||
|
|||||||
@@ -3,14 +3,17 @@ package com.appttude.h_mal.easycc.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 android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import okhttp3.Interceptor
|
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
|
* Interceptor used in network classes to check network status
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
class NetworkConnectionInterceptor(
|
class NetworkConnectionInterceptor(
|
||||||
context: Context
|
context: Context
|
||||||
) : Interceptor {
|
) : Interceptor {
|
||||||
@@ -29,11 +32,22 @@ class NetworkConnectionInterceptor(
|
|||||||
val connectivityManager =
|
val connectivityManager =
|
||||||
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||||
connectivityManager?.let {
|
connectivityManager?.let {
|
||||||
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
result = when {
|
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
||||||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
result = when {
|
||||||
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||||
else -> false
|
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
it.activeNetworkInfo?.run {
|
||||||
|
result = when (type) {
|
||||||
|
ConnectivityManager.TYPE_WIFI -> true
|
||||||
|
ConnectivityManager.TYPE_MOBILE -> true
|
||||||
|
ConnectivityManager.TYPE_ETHERNET -> true
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.appttude.h_mal.easycc.data.network.interceptors
|
package com.appttude.h_mal.easycc.data.network.interceptors
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.appttude.h_mal.easycc.BuildConfig
|
|
||||||
import com.appttude.h_mal.easycc.R
|
import com.appttude.h_mal.easycc.R
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ class PreferenceProvider(context: Context) {
|
|||||||
private val appContext = context.applicationContext
|
private val appContext = context.applicationContext
|
||||||
|
|
||||||
// Instance of Shared preferences
|
// Instance of Shared preferences
|
||||||
private val preference: SharedPreferences
|
private val preference: SharedPreferences =
|
||||||
= PreferenceManager.getDefaultSharedPreferences(appContext)
|
PreferenceManager.getDefaultSharedPreferences(appContext)
|
||||||
|
|
||||||
// Lazy declaration of default rate if no rate is retrieved from
|
// Lazy declaration of default rate if no rate is retrieved from
|
||||||
private val defaultRate: String by lazy {
|
private val defaultRate: String by lazy {
|
||||||
@@ -29,9 +29,9 @@ class PreferenceProvider(context: Context) {
|
|||||||
// Save currency pairs into prefs
|
// Save currency pairs into prefs
|
||||||
fun saveConversionPair(s1: String, s2: String) {
|
fun saveConversionPair(s1: String, s2: String) {
|
||||||
preference.edit()
|
preference.edit()
|
||||||
.putString(CURRENCY_ONE, s1)
|
.putString(CURRENCY_ONE, s1)
|
||||||
.putString(CURRENCY_TWO, s2)
|
.putString(CURRENCY_TWO, s2)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve Currency pairs from prefs
|
// Retrieve Currency pairs from prefs
|
||||||
@@ -46,17 +46,19 @@ class PreferenceProvider(context: Context) {
|
|||||||
|
|
||||||
private fun getConversionString(conversionName: String): String? {
|
private fun getConversionString(conversionName: String): String? {
|
||||||
return preference
|
return preference
|
||||||
.getString(conversionName, defaultRate)
|
.getString(conversionName, defaultRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save currency pairs for widget
|
// Save currency pairs for widget
|
||||||
fun saveWidgetConversionPair(fromString: String,
|
fun saveWidgetConversionPair(
|
||||||
toString: String, appWidgetId: Int) {
|
fromString: String,
|
||||||
|
toString: String, appWidgetId: Int
|
||||||
|
) {
|
||||||
|
|
||||||
preference.edit()
|
preference.edit()
|
||||||
.putString("${appWidgetId}_$CURRENCY_ONE", fromString)
|
.putString("${appWidgetId}_$CURRENCY_ONE", fromString)
|
||||||
.putString("${appWidgetId}_$CURRENCY_TWO", toString)
|
.putString("${appWidgetId}_$CURRENCY_TWO", toString)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve currency pairs for widget
|
// Retrieve currency pairs for widget
|
||||||
@@ -68,17 +70,17 @@ class PreferenceProvider(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getWidgetConversionString(
|
private fun getWidgetConversionString(
|
||||||
appWidgetId: Int, conversionName: String): String? {
|
appWidgetId: Int, conversionName: String
|
||||||
|
): String? {
|
||||||
return preference
|
return preference
|
||||||
.getString("${appWidgetId}_$conversionName", defaultRate)
|
.getString("${appWidgetId}_$conversionName", defaultRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeWidgetConversion(id: Int) {
|
fun removeWidgetConversion(id: Int) {
|
||||||
preference.edit()
|
preference.edit()
|
||||||
.remove("${id}_$CURRENCY_ONE")
|
.remove("${id}_$CURRENCY_ONE")
|
||||||
.remove("${id}_$CURRENCY_TWO")
|
.remove("${id}_$CURRENCY_TWO")
|
||||||
.apply()
|
.apply()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,33 +13,33 @@ import com.appttude.h_mal.easycc.utils.convertPairsListToString
|
|||||||
/**
|
/**
|
||||||
* Default implementation of [Repository]. Single entry point for managing currency' data.
|
* 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 backUpApi: BackupCurrencyApi,
|
private val backUpApi: BackupCurrencyApi,
|
||||||
private val prefs: PreferenceProvider
|
private val prefs: PreferenceProvider
|
||||||
):Repository, SafeApiRequest(){
|
) : Repository, SafeApiRequest() {
|
||||||
|
|
||||||
override suspend fun getDataFromApi(
|
override suspend fun getDataFromApi(
|
||||||
fromCurrency: String,
|
fromCurrency: String,
|
||||||
toCurrency: String
|
toCurrency: String
|
||||||
): ResponseObject{
|
): ResponseObject {
|
||||||
// Set currency pairs as correct string for api query eg. AUD_GBP
|
// Set currency pairs as correct string for api query eg. AUD_GBP
|
||||||
val currencyPair = convertPairsListToString(fromCurrency, toCurrency)
|
val currencyPair = convertPairsListToString(fromCurrency, toCurrency)
|
||||||
return responseUnwrap{ api.getCurrencyRate(currencyPair)}
|
return responseUnwrap { api.getCurrencyRate(currencyPair) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getBackupDataFromApi(
|
override suspend fun getBackupDataFromApi(
|
||||||
fromCurrency: String,
|
fromCurrency: String,
|
||||||
toCurrency: String
|
toCurrency: String
|
||||||
): CurrencyResponse {
|
): CurrencyResponse {
|
||||||
return responseUnwrap{ backUpApi.getCurrencyRate(fromCurrency, toCurrency)}
|
return responseUnwrap { backUpApi.getCurrencyRate(fromCurrency, toCurrency) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getConversionPair(): Pair<String?, String?> {
|
override fun getConversionPair(): Pair<String?, String?> {
|
||||||
return prefs.getConversionPair()
|
return prefs.getConversionPair()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setConversionPair(fromCurrency: String, toCurrency: String){
|
override fun setConversionPair(fromCurrency: String, toCurrency: String) {
|
||||||
prefs.saveConversionPair(fromCurrency, toCurrency)
|
prefs.saveConversionPair(fromCurrency, toCurrency)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,14 +47,16 @@ class RepositoryImpl (
|
|||||||
Resources.getSystem().getStringArray(R.array.currency_arrays)
|
Resources.getSystem().getStringArray(R.array.currency_arrays)
|
||||||
|
|
||||||
override fun getWidgetConversionPairs(appWidgetId: Int): Pair<String?, String?> =
|
override fun getWidgetConversionPairs(appWidgetId: Int): Pair<String?, String?> =
|
||||||
prefs.getWidgetConversionPair(appWidgetId)
|
prefs.getWidgetConversionPair(appWidgetId)
|
||||||
|
|
||||||
override fun setWidgetConversionPairs(fromCurrency: String,
|
override fun setWidgetConversionPairs(
|
||||||
toCurrency: String, appWidgetId: Int) {
|
fromCurrency: String,
|
||||||
|
toCurrency: String, appWidgetId: Int
|
||||||
|
) {
|
||||||
return prefs.saveWidgetConversionPair(fromCurrency, toCurrency, appWidgetId)
|
return prefs.saveWidgetConversionPair(fromCurrency, toCurrency, appWidgetId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeWidgetConversionPairs(id: Int) =
|
override fun removeWidgetConversionPairs(id: Int) =
|
||||||
prefs.removeWidgetConversion(id)
|
prefs.removeWidgetConversion(id)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,16 +2,15 @@ package com.appttude.h_mal.easycc.helper
|
|||||||
|
|
||||||
import com.appttude.h_mal.easycc.data.repository.Repository
|
import com.appttude.h_mal.easycc.data.repository.Repository
|
||||||
import com.appttude.h_mal.easycc.models.CurrencyModelInterface
|
import com.appttude.h_mal.easycc.models.CurrencyModelInterface
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
class CurrencyDataHelper (
|
class CurrencyDataHelper(
|
||||||
val repository: Repository
|
val repository: Repository
|
||||||
){
|
) {
|
||||||
|
|
||||||
suspend fun getDataFromApi(from: String, to: String): CurrencyModelInterface{
|
suspend fun getDataFromApi(from: String, to: String): CurrencyModelInterface {
|
||||||
return try {
|
return try {
|
||||||
repository.getDataFromApi(from, to)
|
repository.getDataFromApi(from, to)
|
||||||
}catch (e: Exception){
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
repository.getBackupDataFromApi(from, to)
|
repository.getBackupDataFromApi(from, to)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,10 @@ import com.appttude.h_mal.easycc.data.repository.Repository
|
|||||||
import com.appttude.h_mal.easycc.models.CurrencyModel
|
import com.appttude.h_mal.easycc.models.CurrencyModel
|
||||||
import com.appttude.h_mal.easycc.utils.trimToThree
|
import com.appttude.h_mal.easycc.utils.trimToThree
|
||||||
|
|
||||||
import kotlin.Exception
|
class WidgetHelper(
|
||||||
|
private val helper: CurrencyDataHelper,
|
||||||
class WidgetHelper (
|
|
||||||
val helper: CurrencyDataHelper,
|
|
||||||
val repository: Repository
|
val repository: Repository
|
||||||
){
|
) {
|
||||||
|
|
||||||
suspend fun getWidgetData(): CurrencyModel? {
|
suspend fun getWidgetData(): CurrencyModel? {
|
||||||
try {
|
try {
|
||||||
@@ -18,13 +16,13 @@ class WidgetHelper (
|
|||||||
val s2 = pair.second?.trimToThree() ?: return null
|
val s2 = pair.second?.trimToThree() ?: return null
|
||||||
|
|
||||||
return helper.getDataFromApi(s1, s2).getCurrencyModel()
|
return helper.getDataFromApi(s1, s2).getCurrencyModel()
|
||||||
}catch (e: Exception){
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeWidgetData(id: Int){
|
fun removeWidgetData(id: Int) {
|
||||||
repository.removeWidgetConversionPairs(id)
|
repository.removeWidgetConversionPairs(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ data class CurrencyModel(
|
|||||||
var rate: Double = 0.0
|
var rate: Double = 0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
interface CurrencyModelInterface{
|
interface CurrencyModelInterface {
|
||||||
fun getCurrencyModel(): CurrencyModel
|
fun getCurrencyModel(): CurrencyModel
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,13 @@ package com.appttude.h_mal.easycc.models
|
|||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class CurrencyObject (
|
data class CurrencyObject(
|
||||||
@SerializedName("id")
|
@SerializedName("id")
|
||||||
var id : String,
|
var id: String,
|
||||||
@SerializedName("fr")
|
@SerializedName("fr")
|
||||||
var fr : String,
|
var fr: String,
|
||||||
@SerializedName("to")
|
@SerializedName("to")
|
||||||
var to : String,
|
var to: String,
|
||||||
@SerializedName("val")
|
@SerializedName("val")
|
||||||
var value: Double
|
var value: Double
|
||||||
)
|
)
|
||||||
@@ -13,9 +13,10 @@ import kotlinx.android.synthetic.main.custom_dialog.*
|
|||||||
/**
|
/**
|
||||||
* Custom dialog when selecting currencies from list with filter
|
* Custom dialog when selecting currencies from list with filter
|
||||||
*/
|
*/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
class CustomDialogClass(
|
class CustomDialogClass(
|
||||||
context: Context,
|
context: Context,
|
||||||
private val clickListener: ClickListener
|
private val clickListener: ClickListener
|
||||||
) : Dialog(context) {
|
) : Dialog(context) {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -29,9 +30,10 @@ class CustomDialogClass(
|
|||||||
|
|
||||||
// array adapter for list of currencies in R.Strings
|
// array adapter for list of currencies in R.Strings
|
||||||
val arrayAdapter =
|
val arrayAdapter =
|
||||||
ArrayAdapter.createFromResource(
|
ArrayAdapter.createFromResource(
|
||||||
context, R.array.currency_arrays,
|
context, R.array.currency_arrays,
|
||||||
android.R.layout.simple_list_item_1)
|
android.R.layout.simple_list_item_1
|
||||||
|
)
|
||||||
|
|
||||||
list_view.adapter = arrayAdapter
|
list_view.adapter = arrayAdapter
|
||||||
|
|
||||||
@@ -41,11 +43,12 @@ class CustomDialogClass(
|
|||||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
|
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
|
||||||
arrayAdapter.filter.filter(charSequence)
|
arrayAdapter.filter.filter(charSequence)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun afterTextChanged(editable: Editable) {}
|
override fun afterTextChanged(editable: Editable) {}
|
||||||
})
|
})
|
||||||
|
|
||||||
// interface selection back to calling activity
|
// interface selection back to calling activity
|
||||||
list_view.setOnItemClickListener{ adapterView, _, i, _ ->
|
list_view.setOnItemClickListener { adapterView, _, i, _ ->
|
||||||
clickListener.onText(adapterView.getItemAtPosition(i).toString())
|
clickListener.onText(adapterView.getItemAtPosition(i).toString())
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
@@ -53,6 +56,6 @@ class CustomDialogClass(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Interface to handle selection within dialog
|
// Interface to handle selection within dialog
|
||||||
interface ClickListener{
|
interface ClickListener {
|
||||||
fun onText(currencyName: String)
|
fun onText(currencyName: String)
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ import org.kodein.di.KodeinAware
|
|||||||
import org.kodein.di.android.kodein
|
import org.kodein.di.android.kodein
|
||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
class MainActivity : AppCompatActivity(), KodeinAware, View.OnClickListener {
|
class MainActivity : AppCompatActivity(), KodeinAware, View.OnClickListener {
|
||||||
|
|
||||||
// Retrieve MainViewModelFactory via dependency injection
|
// Retrieve MainViewModelFactory via dependency injection
|
||||||
@@ -54,10 +55,10 @@ class MainActivity : AppCompatActivity(), KodeinAware, View.OnClickListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpObservers() {
|
private fun setUpObservers() {
|
||||||
viewModel.operationStartedListener.observe(this, Observer {
|
viewModel.operationStartedListener.observe(this, {
|
||||||
progressBar.hideView(false)
|
progressBar.hideView(false)
|
||||||
})
|
})
|
||||||
viewModel.operationFinishedListener.observe(this, Observer { pair ->
|
viewModel.operationFinishedListener.observe(this, { pair ->
|
||||||
// hide progress bar
|
// hide progress bar
|
||||||
progressBar.hideView(true)
|
progressBar.hideView(true)
|
||||||
if (pair.first) {
|
if (pair.first) {
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ import java.io.IOException
|
|||||||
* ViewModel for the task Main Activity Screen
|
* ViewModel for the task Main Activity Screen
|
||||||
*/
|
*/
|
||||||
class MainViewModel(
|
class MainViewModel(
|
||||||
private val currencyDataHelper: CurrencyDataHelper,
|
private val currencyDataHelper: CurrencyDataHelper,
|
||||||
private val repository: Repository
|
private val repository: Repository
|
||||||
) : ViewModel(){
|
) : ViewModel() {
|
||||||
|
|
||||||
private val conversionPairs by lazy { repository.getConversionPair() }
|
private val conversionPairs by lazy { repository.getConversionPair() }
|
||||||
|
|
||||||
@@ -32,17 +32,17 @@ class MainViewModel(
|
|||||||
|
|
||||||
private var conversionRate: Double = 1.00
|
private var conversionRate: Double = 1.00
|
||||||
|
|
||||||
private fun getExchangeRate(){
|
private fun getExchangeRate() {
|
||||||
operationStartedListener.postValue(true)
|
operationStartedListener.postValue(true)
|
||||||
|
|
||||||
// view binded exchange rates selected null checked
|
// view binded exchange rates selected null checked
|
||||||
if (rateIdFrom.isNullOrEmpty() || rateIdTo.isNullOrEmpty()){
|
if (rateIdFrom.isNullOrEmpty() || rateIdTo.isNullOrEmpty()) {
|
||||||
operationFinishedListener.postValue(Pair(false, "Select currencies"))
|
operationFinishedListener.postValue(Pair(false, "Select currencies"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to call api as it will return exchange rate as 1
|
// No need to call api as it will return exchange rate as 1
|
||||||
if (rateIdFrom == rateIdTo){
|
if (rateIdFrom == rateIdTo) {
|
||||||
conversionRate = 1.00
|
conversionRate = 1.00
|
||||||
operationFinishedListener.postValue(Pair(true, null))
|
operationFinishedListener.postValue(Pair(true, null))
|
||||||
return
|
return
|
||||||
@@ -63,7 +63,7 @@ class MainViewModel(
|
|||||||
operationFinishedListener.postValue(Pair(true, null))
|
operationFinishedListener.postValue(Pair(true, null))
|
||||||
return@launch
|
return@launch
|
||||||
}
|
}
|
||||||
}catch(e: IOException){
|
} catch (e: IOException) {
|
||||||
e.message?.let {
|
e.message?.let {
|
||||||
operationFinishedListener.postValue(Pair(false, it))
|
operationFinishedListener.postValue(Pair(false, it))
|
||||||
return@launch
|
return@launch
|
||||||
@@ -78,7 +78,7 @@ class MainViewModel(
|
|||||||
val fromValDouble = fromValue.toDouble()
|
val fromValDouble = fromValue.toDouble()
|
||||||
val bottomVal1 = (fromValDouble * conversionRate)
|
val bottomVal1 = (fromValDouble * conversionRate)
|
||||||
bottomVal1.toTwoDpString()
|
bottomVal1.toTwoDpString()
|
||||||
}catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ class MainViewModel(
|
|||||||
fun getReciprocalConversion(toValue: String): String? {
|
fun getReciprocalConversion(toValue: String): String? {
|
||||||
return try {
|
return try {
|
||||||
val toDoubleVal = toValue.toDouble()
|
val toDoubleVal = toValue.toDouble()
|
||||||
val newTopVal = toDoubleVal.times((1/conversionRate))
|
val newTopVal = toDoubleVal.times((1 / conversionRate))
|
||||||
newTopVal.toTwoDpString()
|
newTopVal.toTwoDpString()
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
null
|
null
|
||||||
@@ -94,11 +94,13 @@ class MainViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start operation based on dialog selection
|
// Start operation based on dialog selection
|
||||||
fun setCurrencyName(tag: Any?, currencyName: String){
|
fun setCurrencyName(tag: Any?, currencyName: String) {
|
||||||
when(tag.toString()){
|
when (tag.toString()) {
|
||||||
"top" -> rateIdFrom = currencyName
|
"top" -> rateIdFrom = currencyName
|
||||||
"bottom" -> rateIdTo = currencyName
|
"bottom" -> rateIdTo = currencyName
|
||||||
else -> { return }
|
else -> {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getExchangeRate()
|
getExchangeRate()
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import com.appttude.h_mal.easycc.helper.CurrencyDataHelper
|
|||||||
* inject repository into viewmodel
|
* inject repository into viewmodel
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class MainViewModelFactory (
|
class MainViewModelFactory(
|
||||||
private val repository: RepositoryImpl,
|
private val repository: RepositoryImpl,
|
||||||
private val helper: CurrencyDataHelper
|
private val helper: CurrencyDataHelper
|
||||||
): ViewModelProvider.NewInstanceFactory(){
|
) : ViewModelProvider.NewInstanceFactory() {
|
||||||
|
|
||||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||||
return MainViewModel(helper, repository) as T
|
return MainViewModel(helper, repository) as T
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ import org.kodein.di.generic.instance
|
|||||||
/**
|
/**
|
||||||
* The configuration screen for the [CurrencyAppWidgetKotlin] AppWidget.
|
* The configuration screen for the [CurrencyAppWidgetKotlin] AppWidget.
|
||||||
*/
|
*/
|
||||||
class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAware, View.OnClickListener {
|
class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAware,
|
||||||
|
View.OnClickListener {
|
||||||
|
|
||||||
override val kodein by kodein()
|
override val kodein by kodein()
|
||||||
private val factory: WidgetViewModelFactory by instance()
|
private val factory: WidgetViewModelFactory by instance()
|
||||||
@@ -47,7 +48,8 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
|||||||
val extras = intent.extras
|
val extras = intent.extras
|
||||||
if (extras != null) {
|
if (extras != null) {
|
||||||
mAppWidgetId = extras.getInt(
|
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.
|
// If this activity was started with an intent without an app widget ID, finish with an error.
|
||||||
@@ -72,12 +74,12 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupObserver() {
|
private fun setupObserver() {
|
||||||
viewModel.operationFinishedListener.observe(this, Observer {
|
viewModel.operationFinishedListener.observe(this, {
|
||||||
|
|
||||||
// it.first is a the success of the operation
|
// it.first is a the success of the operation
|
||||||
if (it.first){
|
if (it.first) {
|
||||||
displaySubmitDialog()
|
displaySubmitDialog()
|
||||||
}else{
|
} else {
|
||||||
// failed operation - display toast with message from it.second
|
// failed operation - display toast with message from it.second
|
||||||
it.second?.let { message -> displayToast(message) }
|
it.second?.let { message -> displayToast(message) }
|
||||||
}
|
}
|
||||||
@@ -87,8 +89,8 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
|||||||
private fun setupDataBinding() {
|
private fun setupDataBinding() {
|
||||||
// data binding to @R.layout.currency_app_widget_configure
|
// data binding to @R.layout.currency_app_widget_configure
|
||||||
DataBindingUtil.setContentView<CurrencyAppWidgetConfigureBinding>(
|
DataBindingUtil.setContentView<CurrencyAppWidgetConfigureBinding>(
|
||||||
this,
|
this,
|
||||||
R.layout.currency_app_widget_configure
|
R.layout.currency_app_widget_configure
|
||||||
).apply {
|
).apply {
|
||||||
viewmodel = viewModel
|
viewmodel = viewModel
|
||||||
lifecycleOwner = this@CurrencyAppWidgetConfigureActivityKotlin
|
lifecycleOwner = this@CurrencyAppWidgetConfigureActivityKotlin
|
||||||
@@ -125,7 +127,7 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
|||||||
}).show()
|
}).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun finishCurrencyWidgetActivity(){
|
fun finishCurrencyWidgetActivity() {
|
||||||
// Make sure we pass back the original appWidgetId
|
// Make sure we pass back the original appWidgetId
|
||||||
val resultValue = intent
|
val resultValue = intent
|
||||||
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId)
|
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId)
|
||||||
@@ -136,8 +138,9 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
|||||||
fun sendUpdateIntent() {
|
fun sendUpdateIntent() {
|
||||||
// It is the responsibility of the configuration activity to update the app widget
|
// It is the responsibility of the configuration activity to update the app widget
|
||||||
// Send update broadcast to widget app class
|
// Send update broadcast to widget app class
|
||||||
Intent(this@CurrencyAppWidgetConfigureActivityKotlin,
|
Intent(
|
||||||
CurrencyAppWidgetKotlin::class.java
|
this@CurrencyAppWidgetConfigureActivityKotlin,
|
||||||
|
CurrencyAppWidgetKotlin::class.java
|
||||||
).apply {
|
).apply {
|
||||||
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||||
viewModel.setWidgetStored()
|
viewModel.setWidgetStored()
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,7 @@ class WidgetSubmitDialog(
|
|||||||
context: Context,
|
context: Context,
|
||||||
private val messageString: String,
|
private val messageString: String,
|
||||||
private val dialogInterface: DialogSubmit
|
private val dialogInterface: DialogSubmit
|
||||||
) :Dialog(context){
|
) : Dialog(context) {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -33,6 +33,6 @@ class WidgetSubmitDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DialogSubmit{
|
interface DialogSubmit {
|
||||||
fun onSubmit()
|
fun onSubmit()
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,8 @@ import com.appttude.h_mal.easycc.data.repository.Repository
|
|||||||
import com.appttude.h_mal.easycc.utils.trimToThree
|
import com.appttude.h_mal.easycc.utils.trimToThree
|
||||||
|
|
||||||
class WidgetViewModel(
|
class WidgetViewModel(
|
||||||
private val repository: Repository
|
private val repository: Repository
|
||||||
) : ViewModel(){
|
) : ViewModel() {
|
||||||
|
|
||||||
private val defaultCurrency: String by lazy { repository.getCurrenciesList()[0] }
|
private val defaultCurrency: String by lazy { repository.getCurrenciesList()[0] }
|
||||||
var appWidgetId: Int? = null
|
var appWidgetId: Int? = null
|
||||||
@@ -21,10 +21,9 @@ class WidgetViewModel(
|
|||||||
|
|
||||||
// Setup viewmodel app widget ID
|
// Setup viewmodel app widget ID
|
||||||
// Set default values for text views
|
// Set default values for text views
|
||||||
fun initiate(appId: Int){
|
fun initiate(appId: Int) {
|
||||||
appWidgetId = appId
|
appWidgetId = appId
|
||||||
val widgetString
|
val widgetString = repository.getWidgetConversionPairs(appId)
|
||||||
= repository.getWidgetConversionPairs(appId)
|
|
||||||
|
|
||||||
rateIdFrom = widgetString.first ?: defaultCurrency
|
rateIdFrom = widgetString.first ?: defaultCurrency
|
||||||
rateIdTo = widgetString.second ?: defaultCurrency
|
rateIdTo = widgetString.second ?: defaultCurrency
|
||||||
@@ -35,33 +34,35 @@ class WidgetViewModel(
|
|||||||
fun getSubmitDialogMessage(): String {
|
fun getSubmitDialogMessage(): String {
|
||||||
val widgetName = getWidgetStringName()
|
val widgetName = getWidgetStringName()
|
||||||
return StringBuilder().append("Create widget for ")
|
return StringBuilder().append("Create widget for ")
|
||||||
.append(widgetName)
|
.append(widgetName)
|
||||||
.append("?").toString()
|
.append("?").toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun submitSelectionOnClick(){
|
fun submitSelectionOnClick() {
|
||||||
if (rateIdTo == null || rateIdFrom == null){
|
if (rateIdTo == null || rateIdFrom == null) {
|
||||||
operationFinishedListener.value = Pair(false, "Selections incomplete")
|
operationFinishedListener.value = Pair(false, "Selections incomplete")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (rateIdFrom == rateIdTo){
|
if (rateIdFrom == rateIdTo) {
|
||||||
operationFinishedListener.value =
|
operationFinishedListener.value =
|
||||||
Pair(false, "Selected rates cannot be the same ${rateIdFrom}${rateIdTo}")
|
Pair(false, "Selected rates cannot be the same ${rateIdFrom}${rateIdTo}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
operationFinishedListener.value = Pair(true, null)
|
operationFinishedListener.value = Pair(true, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWidgetStored() {
|
fun setWidgetStored() {
|
||||||
repository.setWidgetConversionPairs(rateIdFrom!!,rateIdTo!!,appWidgetId!!)
|
repository.setWidgetConversionPairs(rateIdFrom!!, rateIdTo!!, appWidgetId!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start operation based on dialog selection
|
// Start operation based on dialog selection
|
||||||
fun setCurrencyName(tag: Any?, currencyName: String){
|
fun setCurrencyName(tag: Any?, currencyName: String) {
|
||||||
when(tag.toString()){
|
when (tag.toString()) {
|
||||||
"top" -> rateIdFrom = currencyName
|
"top" -> rateIdFrom = currencyName
|
||||||
"bottom" -> rateIdTo = currencyName
|
"bottom" -> rateIdTo = currencyName
|
||||||
else -> { return }
|
else -> {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import com.appttude.h_mal.easycc.data.repository.RepositoryImpl
|
import com.appttude.h_mal.easycc.data.repository.RepositoryImpl
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class WidgetViewModelFactory (
|
class WidgetViewModelFactory(
|
||||||
private val repository: RepositoryImpl
|
private val repository: RepositoryImpl
|
||||||
): ViewModelProvider.NewInstanceFactory(){
|
) : ViewModelProvider.NewInstanceFactory() {
|
||||||
|
|
||||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||||
return WidgetViewModel(repository) as T
|
return WidgetViewModel(repository) as T
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.appttude.h_mal.easycc.utils
|
|||||||
|
|
||||||
import java.lang.Double.valueOf
|
import java.lang.Double.valueOf
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
fun transformIntToArray(int: Int): IntArray{
|
fun transformIntToArray(int: Int): IntArray{
|
||||||
return intArrayOf(int)
|
return intArrayOf(int)
|
||||||
|
|||||||
@@ -5,14 +5,18 @@ import android.view.View
|
|||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
||||||
fun EditText.clearEditText(){
|
fun EditText.clearEditText() {
|
||||||
this.setText("")
|
this.setText("")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun View.hideView(vis : Boolean){
|
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){
|
fun Context.displayToast(message: String) {
|
||||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
package com.appttude.h_mal.easycc.widget
|
package com.appttude.h_mal.easycc.widget
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.appwidget.AppWidgetManager
|
import android.appwidget.AppWidgetManager
|
||||||
import android.appwidget.AppWidgetProvider
|
import android.appwidget.AppWidgetProvider
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
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.helper.WidgetHelper
|
||||||
import com.appttude.h_mal.easycc.ui.main.MainActivity
|
import com.appttude.h_mal.easycc.widget.WidgetServiceIntent.Companion.enqueueWork
|
||||||
import com.appttude.h_mal.easycc.utils.transformIntToArray
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.LateInitKodein
|
import org.kodein.di.LateInitKodein
|
||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
@@ -23,9 +13,8 @@ import org.kodein.di.generic.instance
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of App Widget functionality.
|
* 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() {
|
class CurrencyAppWidgetKotlin : AppWidgetProvider() {
|
||||||
|
|
||||||
@@ -39,12 +28,7 @@ class CurrencyAppWidgetKotlin : AppWidgetProvider() {
|
|||||||
appWidgetManager: AppWidgetManager,
|
appWidgetManager: AppWidgetManager,
|
||||||
appWidgetIds: IntArray
|
appWidgetIds: IntArray
|
||||||
) {
|
) {
|
||||||
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
|
loadWidget(context)
|
||||||
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)
|
|
||||||
}
|
|
||||||
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
super.onUpdate(context, appWidgetManager, appWidgetIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,113 +42,13 @@ class CurrencyAppWidgetKotlin : AppWidgetProvider() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnabled(context: Context) {
|
override fun onEnabled(context: Context) {
|
||||||
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
|
loadWidget(context)
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
super.onEnabled(context)
|
super.onEnabled(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisabled(context: Context) {
|
private fun loadWidget(context: Context) {
|
||||||
kodein.baseKodein = (context.applicationContext as KodeinAware).kodein
|
val mIntent = Intent(context, CurrencyAppWidgetKotlin::class.java)
|
||||||
// Enter relevant functionality for when the last widget is disabled
|
enqueueWork(context, mIntent)
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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.BackupCurrencyApi
|
||||||
import com.appttude.h_mal.easycc.data.network.api.CurrencyApi
|
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.network.response.ResponseObject
|
||||||
import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider
|
import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider
|
||||||
import com.appttude.h_mal.easycc.data.repository.Repository
|
import com.appttude.h_mal.easycc.data.repository.Repository
|
||||||
@@ -23,14 +22,16 @@ import java.io.IOException
|
|||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
|
|
||||||
class RepositoryNetworkTest{
|
class RepositoryNetworkTest {
|
||||||
|
|
||||||
lateinit var repository: Repository
|
lateinit var repository: Repository
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var api: CurrencyApi
|
lateinit var api: CurrencyApi
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var apiBackup: BackupCurrencyApi
|
lateinit var apiBackup: BackupCurrencyApi
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var prefs: PreferenceProvider
|
lateinit var prefs: PreferenceProvider
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ class RepositoryNetworkTest{
|
|||||||
Mockito.`when`(api.getCurrencyRate(currencyPair)).thenReturn(re)
|
Mockito.`when`(api.getCurrencyRate(currencyPair)).thenReturn(re)
|
||||||
|
|
||||||
//THEN - the unwrapped login response contains the correct values
|
//THEN - the unwrapped login response contains the correct values
|
||||||
val currencyResponse = repository.getDataFromApi(s1,s2)
|
val currencyResponse = repository.getDataFromApi(s1, s2)
|
||||||
assertNotNull(currencyResponse)
|
assertNotNull(currencyResponse)
|
||||||
assertEquals(currencyResponse, mockCurrencyResponse)
|
assertEquals(currencyResponse, mockCurrencyResponse)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.appttude.h_mal.easycc.repository
|
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.BackupCurrencyApi
|
||||||
import com.appttude.h_mal.easycc.data.network.api.CurrencyApi
|
import com.appttude.h_mal.easycc.data.network.api.CurrencyApi
|
||||||
import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider
|
import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider
|
||||||
@@ -19,8 +18,10 @@ class RepositoryStorageTest {
|
|||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var api: CurrencyApi
|
lateinit var api: CurrencyApi
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var apiBackup: BackupCurrencyApi
|
lateinit var apiBackup: BackupCurrencyApi
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
lateinit var prefs: PreferenceProvider
|
lateinit var prefs: PreferenceProvider
|
||||||
|
|
||||||
|
|||||||
@@ -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.network.response.ResponseObject
|
||||||
import com.appttude.h_mal.easycc.data.repository.Repository
|
import com.appttude.h_mal.easycc.data.repository.Repository
|
||||||
import com.appttude.h_mal.easycc.helper.CurrencyDataHelper
|
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 com.appttude.h_mal.easycc.utils.observeOnce
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
@@ -38,7 +38,7 @@ class MainViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun initiate_validBundleValues_successResponse() = runBlocking{
|
fun initiate_validBundleValues_successResponse() = runBlocking {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val currencyOne = "AUD - Australian Dollar"
|
val currencyOne = "AUD - Australian Dollar"
|
||||||
val currencyTwo = "GBP - British Pound"
|
val currencyTwo = "GBP - British Pound"
|
||||||
@@ -48,7 +48,8 @@ class MainViewModelTest {
|
|||||||
//WHEN
|
//WHEN
|
||||||
Mockito.`when`(bundle.getString("parse_1")).thenReturn(currencyOne)
|
Mockito.`when`(bundle.getString("parse_1")).thenReturn(currencyOne)
|
||||||
Mockito.`when`(bundle.getString("parse_2")).thenReturn(currencyTwo)
|
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
|
//THEN
|
||||||
viewModel.initiate(bundle)
|
viewModel.initiate(bundle)
|
||||||
@@ -62,7 +63,7 @@ class MainViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun initiate_invalidBundleValues_successfulResponse() = runBlocking{
|
fun initiate_invalidBundleValues_successfulResponse() = runBlocking {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val currencyOne = "AUD - Australian Dollar"
|
val currencyOne = "AUD - Australian Dollar"
|
||||||
val currencyTwo = "GBP - British Pound"
|
val currencyTwo = "GBP - British Pound"
|
||||||
@@ -71,7 +72,8 @@ class MainViewModelTest {
|
|||||||
|
|
||||||
//WHEN
|
//WHEN
|
||||||
Mockito.`when`(repository.getConversionPair()).thenReturn(pair)
|
Mockito.`when`(repository.getConversionPair()).thenReturn(pair)
|
||||||
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
|
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
|
||||||
|
.thenReturn(responseObject)
|
||||||
|
|
||||||
//THEN
|
//THEN
|
||||||
viewModel.initiate(null)
|
viewModel.initiate(null)
|
||||||
@@ -85,7 +87,7 @@ class MainViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun initiate_sameBundleValues_successfulResponse() = runBlocking{
|
fun initiate_sameBundleValues_successfulResponse() = runBlocking {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val currencyOne = "AUD - Australian Dollar"
|
val currencyOne = "AUD - Australian Dollar"
|
||||||
val bundle = mock(Bundle()::class.java)
|
val bundle = mock(Bundle()::class.java)
|
||||||
@@ -128,9 +130,8 @@ class MainViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setCurrencyName_validValues_successResponse() = runBlocking{
|
fun setCurrencyName_validValues_successResponse() = runBlocking {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val currencyOne = "AUD - Australian Dollar"
|
val currencyOne = "AUD - Australian Dollar"
|
||||||
val currencyTwo = "GBP - British Pound"
|
val currencyTwo = "GBP - British Pound"
|
||||||
@@ -139,7 +140,8 @@ class MainViewModelTest {
|
|||||||
val responseObject = mock(ResponseObject::class.java)
|
val responseObject = mock(ResponseObject::class.java)
|
||||||
|
|
||||||
//WHEN
|
//WHEN
|
||||||
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
|
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
|
||||||
|
.thenReturn(responseObject)
|
||||||
|
|
||||||
//THEN
|
//THEN
|
||||||
viewModel.setCurrencyName(tag, currencyOne)
|
viewModel.setCurrencyName(tag, currencyOne)
|
||||||
@@ -154,7 +156,7 @@ class MainViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setCurrencyName_sameValues_successfulResponse() = runBlocking{
|
fun setCurrencyName_sameValues_successfulResponse() = runBlocking {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val currencyOne = "AUD - Australian Dollar"
|
val currencyOne = "AUD - Australian Dollar"
|
||||||
val currencyTwo = "GBP - British Pound"
|
val currencyTwo = "GBP - British Pound"
|
||||||
@@ -163,7 +165,8 @@ class MainViewModelTest {
|
|||||||
val responseObject = mock(ResponseObject::class.java)
|
val responseObject = mock(ResponseObject::class.java)
|
||||||
|
|
||||||
//WHEN
|
//WHEN
|
||||||
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
|
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
|
||||||
|
.thenReturn(responseObject)
|
||||||
|
|
||||||
//THEN
|
//THEN
|
||||||
viewModel.setCurrencyName(tag, currencyOne)
|
viewModel.setCurrencyName(tag, currencyOne)
|
||||||
@@ -177,7 +180,7 @@ class MainViewModelTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun setCurrencyName_invalidValues_unsuccessfulResponse() = runBlocking{
|
fun setCurrencyName_invalidValues_unsuccessfulResponse() = runBlocking {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val currencyOne = "AUD - Australian Dollar"
|
val currencyOne = "AUD - Australian Dollar"
|
||||||
val currencyTwo = "GBP - British Pound"
|
val currencyTwo = "GBP - British Pound"
|
||||||
@@ -185,7 +188,8 @@ class MainViewModelTest {
|
|||||||
val responseObject = mock(ResponseObject::class.java)
|
val responseObject = mock(ResponseObject::class.java)
|
||||||
|
|
||||||
//WHEN
|
//WHEN
|
||||||
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo)).thenReturn(responseObject)
|
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
|
||||||
|
.thenReturn(responseObject)
|
||||||
|
|
||||||
//THEN
|
//THEN
|
||||||
viewModel.setCurrencyName(tag, currencyOne)
|
viewModel.setCurrencyName(tag, currencyOne)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package com.appttude.h_mal.easycc.ui.widget
|
|||||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import com.appttude.h_mal.easycc.data.repository.Repository
|
import com.appttude.h_mal.easycc.data.repository.Repository
|
||||||
import com.appttude.h_mal.easycc.utils.observeOnce
|
import com.appttude.h_mal.easycc.utils.observeOnce
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Assert.*
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
@@ -14,6 +14,7 @@ import org.mockito.MockitoAnnotations
|
|||||||
|
|
||||||
private const val currencyOne = "AUD - Australian Dollar"
|
private const val currencyOne = "AUD - Australian Dollar"
|
||||||
private const val currencyTwo = "GBP - British Pound"
|
private const val currencyTwo = "GBP - British Pound"
|
||||||
|
|
||||||
class WidgetViewModelTest {
|
class WidgetViewModelTest {
|
||||||
|
|
||||||
// Run tasks synchronously
|
// Run tasks synchronously
|
||||||
@@ -35,7 +36,7 @@ class WidgetViewModelTest {
|
|||||||
fun initiate_validInput_successfulResponse() {
|
fun initiate_validInput_successfulResponse() {
|
||||||
//GIVEN
|
//GIVEN
|
||||||
val appId = 123
|
val appId = 123
|
||||||
val pair = Pair(currencyOne,currencyTwo)
|
val pair = Pair(currencyOne, currencyTwo)
|
||||||
|
|
||||||
//WHEN
|
//WHEN
|
||||||
Mockito.`when`(repository.getWidgetConversionPairs(appId)).thenReturn(pair)
|
Mockito.`when`(repository.getWidgetConversionPairs(appId)).thenReturn(pair)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.appttude.h_mal.easycc
|
package com.appttude.h_mal.easycc.utils
|
||||||
|
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.appttude.h_mal.easycc.utils
|
package com.appttude.h_mal.easycc.utils
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import com.appttude.h_mal.easycc.OneTimeObserver
|
|
||||||
|
|
||||||
fun <T> LiveData<T>.observeOnce(onChangeHandler: (T) -> Unit) {
|
fun <T> LiveData<T>.observeOnce(onChangeHandler: (T) -> Unit) {
|
||||||
val observer = OneTimeObserver(handler = onChangeHandler)
|
val observer = OneTimeObserver(handler = onChangeHandler)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.61'
|
ext.kotlin_version = '1.4.10'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
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
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
#Thu Mar 05 18:27:33 UTC 2020
|
#Sat Jun 12 22:27:25 BST 2021
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user