mirror of
https://github.com/hmalik144/EasyCC_Master.git
synced 2025-12-10 03:05:29 +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 {
|
||||
|
||||
// Kodein Dependecy Injection singletons and providers created
|
||||
// KODEIN DI components declaration
|
||||
override val kodein by Kodein.lazy {
|
||||
import(androidXModule(this@AppClass))
|
||||
|
||||
|
||||
@@ -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,11 +9,10 @@ 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(
|
||||
call: suspend () -> Response<T>
|
||||
call: suspend () -> Response<T>
|
||||
): T {
|
||||
val response = call.invoke()
|
||||
|
||||
@@ -34,21 +32,17 @@ abstract class SafeApiRequest {
|
||||
val errorMessageString = errorBody.getError()
|
||||
|
||||
//build a log message to log in console
|
||||
val log = if (errorMessageString.isNullOrEmpty()){
|
||||
val log = if (errorMessageString.isNullOrEmpty()) {
|
||||
errorCode
|
||||
}else{
|
||||
} else {
|
||||
StringBuilder()
|
||||
.append(errorCode)
|
||||
.append("\n")
|
||||
.append(errorMessageString)
|
||||
.toString()
|
||||
.append(errorCode)
|
||||
.append("\n")
|
||||
.append(errorMessageString)
|
||||
.toString()
|
||||
}
|
||||
print(log)
|
||||
|
||||
// Log.e("Api Response Error", log)
|
||||
|
||||
//return error message
|
||||
//if null return error code
|
||||
return errorMessageString ?: errorCode
|
||||
}
|
||||
|
||||
|
||||
@@ -11,39 +11,34 @@ 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{
|
||||
companion object {
|
||||
operator fun invoke(
|
||||
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||
interceptor: HttpLoggingInterceptor
|
||||
) : BackupCurrencyApi{
|
||||
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||
interceptor: HttpLoggingInterceptor
|
||||
): BackupCurrencyApi {
|
||||
|
||||
val okkHttpclient = OkHttpClient.Builder()
|
||||
.addInterceptor(interceptor)
|
||||
.addNetworkInterceptor(networkConnectionInterceptor)
|
||||
.build()
|
||||
.addInterceptor(interceptor)
|
||||
.addNetworkInterceptor(networkConnectionInterceptor)
|
||||
.build()
|
||||
|
||||
// Build retrofit
|
||||
return Retrofit.Builder()
|
||||
.client(okkHttpclient)
|
||||
.baseUrl("https://api.frankfurter.app/")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(BackupCurrencyApi::class.java)
|
||||
.client(okkHttpclient)
|
||||
.baseUrl("https://api.frankfurter.app/")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(BackupCurrencyApi::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -21,21 +21,19 @@ interface CurrencyApi {
|
||||
suspend fun getCurrencyRate(@Query("q") currency: String): Response<ResponseObject>
|
||||
|
||||
// interface invokation to be used in application class
|
||||
companion object{
|
||||
companion object {
|
||||
operator fun invoke(
|
||||
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||
queryInterceptor: QueryInterceptor,
|
||||
interceptor: HttpLoggingInterceptor
|
||||
) : CurrencyApi{
|
||||
): 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/")
|
||||
|
||||
@@ -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,11 +32,22 @@ class NetworkConnectionInterceptor(
|
||||
val connectivityManager =
|
||||
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||
connectivityManager?.let {
|
||||
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
||||
result = when {
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||
else -> false
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
||||
result = when {
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||
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
|
||||
|
||||
import android.content.Context
|
||||
import com.appttude.h_mal.easycc.BuildConfig
|
||||
import com.appttude.h_mal.easycc.R
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Interceptor
|
||||
|
||||
@@ -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 {
|
||||
@@ -29,9 +29,9 @@ class PreferenceProvider(context: Context) {
|
||||
// Save currency pairs into prefs
|
||||
fun saveConversionPair(s1: String, s2: String) {
|
||||
preference.edit()
|
||||
.putString(CURRENCY_ONE, s1)
|
||||
.putString(CURRENCY_TWO, s2)
|
||||
.apply()
|
||||
.putString(CURRENCY_ONE, s1)
|
||||
.putString(CURRENCY_TWO, s2)
|
||||
.apply()
|
||||
}
|
||||
|
||||
// Retrieve Currency pairs from prefs
|
||||
@@ -46,17 +46,19 @@ class PreferenceProvider(context: Context) {
|
||||
|
||||
private fun getConversionString(conversionName: String): String? {
|
||||
return preference
|
||||
.getString(conversionName, defaultRate)
|
||||
.getString(conversionName, defaultRate)
|
||||
}
|
||||
|
||||
// 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)
|
||||
.putString("${appWidgetId}_$CURRENCY_TWO", toString)
|
||||
.apply()
|
||||
.putString("${appWidgetId}_$CURRENCY_ONE", fromString)
|
||||
.putString("${appWidgetId}_$CURRENCY_TWO", toString)
|
||||
.apply()
|
||||
}
|
||||
|
||||
// Retrieve currency pairs for widget
|
||||
@@ -68,17 +70,17 @@ class PreferenceProvider(context: Context) {
|
||||
}
|
||||
|
||||
private fun getWidgetConversionString(
|
||||
appWidgetId: Int, conversionName: String): String? {
|
||||
appWidgetId: Int, conversionName: String
|
||||
): String? {
|
||||
return preference
|
||||
.getString("${appWidgetId}_$conversionName", defaultRate)
|
||||
.getString("${appWidgetId}_$conversionName", defaultRate)
|
||||
}
|
||||
|
||||
fun removeWidgetConversion(id: Int) {
|
||||
preference.edit()
|
||||
.remove("${id}_$CURRENCY_ONE")
|
||||
.remove("${id}_$CURRENCY_TWO")
|
||||
.apply()
|
||||
|
||||
.remove("${id}_$CURRENCY_ONE")
|
||||
.remove("${id}_$CURRENCY_TWO")
|
||||
.apply()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,33 +13,33 @@ import com.appttude.h_mal.easycc.utils.convertPairsListToString
|
||||
/**
|
||||
* Default implementation of [Repository]. Single entry point for managing currency' data.
|
||||
*/
|
||||
class RepositoryImpl (
|
||||
class RepositoryImpl(
|
||||
private val api: CurrencyApi,
|
||||
private val backUpApi: BackupCurrencyApi,
|
||||
private val prefs: PreferenceProvider
|
||||
):Repository, SafeApiRequest(){
|
||||
) : Repository, SafeApiRequest() {
|
||||
|
||||
override suspend fun getDataFromApi(
|
||||
fromCurrency: String,
|
||||
toCurrency: String
|
||||
): ResponseObject{
|
||||
): ResponseObject {
|
||||
// Set currency pairs as correct string for api query eg. AUD_GBP
|
||||
val currencyPair = convertPairsListToString(fromCurrency, toCurrency)
|
||||
return responseUnwrap{ api.getCurrencyRate(currencyPair)}
|
||||
return responseUnwrap { api.getCurrencyRate(currencyPair) }
|
||||
}
|
||||
|
||||
override suspend fun getBackupDataFromApi(
|
||||
fromCurrency: String,
|
||||
toCurrency: String
|
||||
): CurrencyResponse {
|
||||
return responseUnwrap{ backUpApi.getCurrencyRate(fromCurrency, toCurrency)}
|
||||
return responseUnwrap { backUpApi.getCurrencyRate(fromCurrency, toCurrency) }
|
||||
}
|
||||
|
||||
override fun getConversionPair(): Pair<String?, String?> {
|
||||
return prefs.getConversionPair()
|
||||
}
|
||||
|
||||
override fun setConversionPair(fromCurrency: String, toCurrency: String){
|
||||
override fun setConversionPair(fromCurrency: String, toCurrency: String) {
|
||||
prefs.saveConversionPair(fromCurrency, toCurrency)
|
||||
}
|
||||
|
||||
@@ -47,14 +47,16 @@ class RepositoryImpl (
|
||||
Resources.getSystem().getStringArray(R.array.currency_arrays)
|
||||
|
||||
override fun getWidgetConversionPairs(appWidgetId: Int): Pair<String?, String?> =
|
||||
prefs.getWidgetConversionPair(appWidgetId)
|
||||
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)
|
||||
}
|
||||
|
||||
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.models.CurrencyModelInterface
|
||||
import java.lang.Exception
|
||||
|
||||
class CurrencyDataHelper (
|
||||
class CurrencyDataHelper(
|
||||
val repository: Repository
|
||||
){
|
||||
) {
|
||||
|
||||
suspend fun getDataFromApi(from: String, to: String): CurrencyModelInterface{
|
||||
suspend fun getDataFromApi(from: String, to: String): CurrencyModelInterface {
|
||||
return try {
|
||||
repository.getDataFromApi(from, to)
|
||||
}catch (e: Exception){
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
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.utils.trimToThree
|
||||
|
||||
import kotlin.Exception
|
||||
|
||||
class WidgetHelper (
|
||||
val helper: CurrencyDataHelper,
|
||||
class WidgetHelper(
|
||||
private val helper: CurrencyDataHelper,
|
||||
val repository: Repository
|
||||
){
|
||||
) {
|
||||
|
||||
suspend fun getWidgetData(): CurrencyModel? {
|
||||
try {
|
||||
@@ -18,13 +16,13 @@ class WidgetHelper (
|
||||
val s2 = pair.second?.trimToThree() ?: return null
|
||||
|
||||
return helper.getDataFromApi(s1, s2).getCurrencyModel()
|
||||
}catch (e: Exception){
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
fun removeWidgetData(id: Int){
|
||||
fun removeWidgetData(id: Int) {
|
||||
repository.removeWidgetConversionPairs(id)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,6 @@ data class CurrencyModel(
|
||||
var rate: Double = 0.0
|
||||
)
|
||||
|
||||
interface CurrencyModelInterface{
|
||||
interface CurrencyModelInterface {
|
||||
fun getCurrencyModel(): CurrencyModel
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package com.appttude.h_mal.easycc.models
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class CurrencyObject (
|
||||
data class CurrencyObject(
|
||||
@SerializedName("id")
|
||||
var id : String,
|
||||
var id: String,
|
||||
@SerializedName("fr")
|
||||
var fr : String,
|
||||
var fr: String,
|
||||
@SerializedName("to")
|
||||
var to : String,
|
||||
var to: String,
|
||||
@SerializedName("val")
|
||||
var value: Double
|
||||
)
|
||||
@@ -13,9 +13,10 @@ 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
|
||||
context: Context,
|
||||
private val clickListener: ClickListener
|
||||
) : Dialog(context) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@@ -29,9 +30,10 @@ class CustomDialogClass(
|
||||
|
||||
// array adapter for list of currencies in R.Strings
|
||||
val arrayAdapter =
|
||||
ArrayAdapter.createFromResource(
|
||||
context, R.array.currency_arrays,
|
||||
android.R.layout.simple_list_item_1)
|
||||
ArrayAdapter.createFromResource(
|
||||
context, R.array.currency_arrays,
|
||||
android.R.layout.simple_list_item_1
|
||||
)
|
||||
|
||||
list_view.adapter = arrayAdapter
|
||||
|
||||
@@ -41,11 +43,12 @@ class CustomDialogClass(
|
||||
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
|
||||
arrayAdapter.filter.filter(charSequence)
|
||||
}
|
||||
|
||||
override fun afterTextChanged(editable: Editable) {}
|
||||
})
|
||||
|
||||
// interface selection back to calling activity
|
||||
list_view.setOnItemClickListener{ adapterView, _, i, _ ->
|
||||
list_view.setOnItemClickListener { adapterView, _, i, _ ->
|
||||
clickListener.onText(adapterView.getItemAtPosition(i).toString())
|
||||
dismiss()
|
||||
}
|
||||
@@ -53,6 +56,6 @@ class CustomDialogClass(
|
||||
}
|
||||
|
||||
// Interface to handle selection within dialog
|
||||
interface ClickListener{
|
||||
interface ClickListener {
|
||||
fun onText(currencyName: String)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -16,9 +16,9 @@ import java.io.IOException
|
||||
* ViewModel for the task Main Activity Screen
|
||||
*/
|
||||
class MainViewModel(
|
||||
private val currencyDataHelper: CurrencyDataHelper,
|
||||
private val repository: Repository
|
||||
) : ViewModel(){
|
||||
private val currencyDataHelper: CurrencyDataHelper,
|
||||
private val repository: Repository
|
||||
) : ViewModel() {
|
||||
|
||||
private val conversionPairs by lazy { repository.getConversionPair() }
|
||||
|
||||
@@ -32,17 +32,17 @@ class MainViewModel(
|
||||
|
||||
private var conversionRate: Double = 1.00
|
||||
|
||||
private fun getExchangeRate(){
|
||||
private fun getExchangeRate() {
|
||||
operationStartedListener.postValue(true)
|
||||
|
||||
// view binded exchange rates selected null checked
|
||||
if (rateIdFrom.isNullOrEmpty() || rateIdTo.isNullOrEmpty()){
|
||||
if (rateIdFrom.isNullOrEmpty() || rateIdTo.isNullOrEmpty()) {
|
||||
operationFinishedListener.postValue(Pair(false, "Select currencies"))
|
||||
return
|
||||
}
|
||||
|
||||
// No need to call api as it will return exchange rate as 1
|
||||
if (rateIdFrom == rateIdTo){
|
||||
if (rateIdFrom == rateIdTo) {
|
||||
conversionRate = 1.00
|
||||
operationFinishedListener.postValue(Pair(true, null))
|
||||
return
|
||||
@@ -63,7 +63,7 @@ class MainViewModel(
|
||||
operationFinishedListener.postValue(Pair(true, null))
|
||||
return@launch
|
||||
}
|
||||
}catch(e: IOException){
|
||||
} catch (e: IOException) {
|
||||
e.message?.let {
|
||||
operationFinishedListener.postValue(Pair(false, it))
|
||||
return@launch
|
||||
@@ -78,7 +78,7 @@ class MainViewModel(
|
||||
val fromValDouble = fromValue.toDouble()
|
||||
val bottomVal1 = (fromValDouble * conversionRate)
|
||||
bottomVal1.toTwoDpString()
|
||||
}catch (e: NumberFormatException) {
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class MainViewModel(
|
||||
fun getReciprocalConversion(toValue: String): String? {
|
||||
return try {
|
||||
val toDoubleVal = toValue.toDouble()
|
||||
val newTopVal = toDoubleVal.times((1/conversionRate))
|
||||
val newTopVal = toDoubleVal.times((1 / conversionRate))
|
||||
newTopVal.toTwoDpString()
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
@@ -94,11 +94,13 @@ class MainViewModel(
|
||||
}
|
||||
|
||||
// Start operation based on dialog selection
|
||||
fun setCurrencyName(tag: Any?, currencyName: String){
|
||||
when(tag.toString()){
|
||||
fun setCurrencyName(tag: Any?, currencyName: String) {
|
||||
when (tag.toString()) {
|
||||
"top" -> rateIdFrom = currencyName
|
||||
"bottom" -> rateIdTo = currencyName
|
||||
else -> { return }
|
||||
else -> {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
getExchangeRate()
|
||||
|
||||
@@ -10,10 +10,10 @@ import com.appttude.h_mal.easycc.helper.CurrencyDataHelper
|
||||
* inject repository into viewmodel
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class MainViewModelFactory (
|
||||
private val repository: RepositoryImpl,
|
||||
private val helper: CurrencyDataHelper
|
||||
): ViewModelProvider.NewInstanceFactory(){
|
||||
class MainViewModelFactory(
|
||||
private val repository: RepositoryImpl,
|
||||
private val helper: CurrencyDataHelper
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return MainViewModel(helper, repository) as T
|
||||
|
||||
@@ -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,12 +74,12 @@ 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){
|
||||
if (it.first) {
|
||||
displaySubmitDialog()
|
||||
}else{
|
||||
} else {
|
||||
// failed operation - display toast with message from it.second
|
||||
it.second?.let { message -> displayToast(message) }
|
||||
}
|
||||
@@ -87,8 +89,8 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
||||
private fun setupDataBinding() {
|
||||
// data binding to @R.layout.currency_app_widget_configure
|
||||
DataBindingUtil.setContentView<CurrencyAppWidgetConfigureBinding>(
|
||||
this,
|
||||
R.layout.currency_app_widget_configure
|
||||
this,
|
||||
R.layout.currency_app_widget_configure
|
||||
).apply {
|
||||
viewmodel = viewModel
|
||||
lifecycleOwner = this@CurrencyAppWidgetConfigureActivityKotlin
|
||||
@@ -125,7 +127,7 @@ class CurrencyAppWidgetConfigureActivityKotlin : AppCompatActivity(), KodeinAwar
|
||||
}).show()
|
||||
}
|
||||
|
||||
fun finishCurrencyWidgetActivity(){
|
||||
fun finishCurrencyWidgetActivity() {
|
||||
// Make sure we pass back the original appWidgetId
|
||||
val resultValue = intent
|
||||
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId)
|
||||
@@ -136,8 +138,9 @@ 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,
|
||||
CurrencyAppWidgetKotlin::class.java
|
||||
Intent(
|
||||
this@CurrencyAppWidgetConfigureActivityKotlin,
|
||||
CurrencyAppWidgetKotlin::class.java
|
||||
).apply {
|
||||
action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
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,
|
||||
private val messageString: String,
|
||||
private val dialogInterface: DialogSubmit
|
||||
) :Dialog(context){
|
||||
) : Dialog(context) {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -33,6 +33,6 @@ class WidgetSubmitDialog(
|
||||
}
|
||||
}
|
||||
|
||||
interface DialogSubmit{
|
||||
interface DialogSubmit {
|
||||
fun onSubmit()
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import com.appttude.h_mal.easycc.data.repository.Repository
|
||||
import com.appttude.h_mal.easycc.utils.trimToThree
|
||||
|
||||
class WidgetViewModel(
|
||||
private val repository: Repository
|
||||
) : ViewModel(){
|
||||
private val repository: Repository
|
||||
) : ViewModel() {
|
||||
|
||||
private val defaultCurrency: String by lazy { repository.getCurrenciesList()[0] }
|
||||
var appWidgetId: Int? = null
|
||||
@@ -21,10 +21,9 @@ class WidgetViewModel(
|
||||
|
||||
// Setup viewmodel app widget ID
|
||||
// Set default values for text views
|
||||
fun initiate(appId: Int){
|
||||
fun initiate(appId: Int) {
|
||||
appWidgetId = appId
|
||||
val widgetString
|
||||
= repository.getWidgetConversionPairs(appId)
|
||||
val widgetString = repository.getWidgetConversionPairs(appId)
|
||||
|
||||
rateIdFrom = widgetString.first ?: defaultCurrency
|
||||
rateIdTo = widgetString.second ?: defaultCurrency
|
||||
@@ -35,33 +34,35 @@ class WidgetViewModel(
|
||||
fun getSubmitDialogMessage(): String {
|
||||
val widgetName = getWidgetStringName()
|
||||
return StringBuilder().append("Create widget for ")
|
||||
.append(widgetName)
|
||||
.append("?").toString()
|
||||
.append(widgetName)
|
||||
.append("?").toString()
|
||||
}
|
||||
|
||||
fun submitSelectionOnClick(){
|
||||
if (rateIdTo == null || rateIdFrom == null){
|
||||
fun submitSelectionOnClick() {
|
||||
if (rateIdTo == null || rateIdFrom == null) {
|
||||
operationFinishedListener.value = Pair(false, "Selections incomplete")
|
||||
return
|
||||
}
|
||||
if (rateIdFrom == rateIdTo){
|
||||
if (rateIdFrom == rateIdTo) {
|
||||
operationFinishedListener.value =
|
||||
Pair(false, "Selected rates cannot be the same ${rateIdFrom}${rateIdTo}")
|
||||
Pair(false, "Selected rates cannot be the same ${rateIdFrom}${rateIdTo}")
|
||||
return
|
||||
}
|
||||
operationFinishedListener.value = Pair(true, null)
|
||||
}
|
||||
|
||||
fun setWidgetStored() {
|
||||
repository.setWidgetConversionPairs(rateIdFrom!!,rateIdTo!!,appWidgetId!!)
|
||||
repository.setWidgetConversionPairs(rateIdFrom!!, rateIdTo!!, appWidgetId!!)
|
||||
}
|
||||
|
||||
// Start operation based on dialog selection
|
||||
fun setCurrencyName(tag: Any?, currencyName: String){
|
||||
when(tag.toString()){
|
||||
fun setCurrencyName(tag: Any?, currencyName: String) {
|
||||
when (tag.toString()) {
|
||||
"top" -> rateIdFrom = 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
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class WidgetViewModelFactory (
|
||||
private val repository: RepositoryImpl
|
||||
): ViewModelProvider.NewInstanceFactory(){
|
||||
class WidgetViewModelFactory(
|
||||
private val repository: RepositoryImpl
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
return WidgetViewModel(repository) as T
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -5,14 +5,18 @@ import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
|
||||
fun EditText.clearEditText(){
|
||||
fun EditText.clearEditText() {
|
||||
this.setText("")
|
||||
}
|
||||
|
||||
fun View.hideView(vis : Boolean){
|
||||
visibility = if (vis){ View.GONE } else { View.VISIBLE }
|
||||
fun View.hideView(vis: Boolean) {
|
||||
visibility = if (vis) {
|
||||
View.GONE
|
||||
} else {
|
||||
View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.displayToast(message: String){
|
||||
fun Context.displayToast(message: String) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.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
|
||||
@@ -23,14 +22,16 @@ import java.io.IOException
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
|
||||
class RepositoryNetworkTest{
|
||||
class RepositoryNetworkTest {
|
||||
|
||||
lateinit var repository: Repository
|
||||
|
||||
@Mock
|
||||
lateinit var api: CurrencyApi
|
||||
|
||||
@Mock
|
||||
lateinit var apiBackup: BackupCurrencyApi
|
||||
|
||||
@Mock
|
||||
lateinit var prefs: PreferenceProvider
|
||||
|
||||
@@ -54,7 +55,7 @@ class RepositoryNetworkTest{
|
||||
Mockito.`when`(api.getCurrencyRate(currencyPair)).thenReturn(re)
|
||||
|
||||
//THEN - the unwrapped login response contains the correct values
|
||||
val currencyResponse = repository.getDataFromApi(s1,s2)
|
||||
val currencyResponse = repository.getDataFromApi(s1, s2)
|
||||
assertNotNull(currencyResponse)
|
||||
assertEquals(currencyResponse, mockCurrencyResponse)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -38,7 +38,7 @@ class MainViewModelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initiate_validBundleValues_successResponse() = runBlocking{
|
||||
fun initiate_validBundleValues_successResponse() = runBlocking {
|
||||
//GIVEN
|
||||
val currencyOne = "AUD - Australian Dollar"
|
||||
val currencyTwo = "GBP - British Pound"
|
||||
@@ -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)
|
||||
@@ -62,7 +63,7 @@ class MainViewModelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initiate_invalidBundleValues_successfulResponse() = runBlocking{
|
||||
fun initiate_invalidBundleValues_successfulResponse() = runBlocking {
|
||||
//GIVEN
|
||||
val currencyOne = "AUD - Australian Dollar"
|
||||
val currencyTwo = "GBP - British Pound"
|
||||
@@ -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)
|
||||
@@ -85,7 +87,7 @@ class MainViewModelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun initiate_sameBundleValues_successfulResponse() = runBlocking{
|
||||
fun initiate_sameBundleValues_successfulResponse() = runBlocking {
|
||||
//GIVEN
|
||||
val currencyOne = "AUD - Australian Dollar"
|
||||
val bundle = mock(Bundle()::class.java)
|
||||
@@ -128,9 +130,8 @@ class MainViewModelTest {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
fun setCurrencyName_validValues_successResponse() = runBlocking{
|
||||
fun setCurrencyName_validValues_successResponse() = runBlocking {
|
||||
//GIVEN
|
||||
val currencyOne = "AUD - Australian Dollar"
|
||||
val currencyTwo = "GBP - British Pound"
|
||||
@@ -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)
|
||||
@@ -154,7 +156,7 @@ class MainViewModelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setCurrencyName_sameValues_successfulResponse() = runBlocking{
|
||||
fun setCurrencyName_sameValues_successfulResponse() = runBlocking {
|
||||
//GIVEN
|
||||
val currencyOne = "AUD - Australian Dollar"
|
||||
val currencyTwo = "GBP - British Pound"
|
||||
@@ -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)
|
||||
@@ -177,7 +180,7 @@ class MainViewModelTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setCurrencyName_invalidValues_unsuccessfulResponse() = runBlocking{
|
||||
fun setCurrencyName_invalidValues_unsuccessfulResponse() = runBlocking {
|
||||
//GIVEN
|
||||
val currencyOne = "AUD - Australian Dollar"
|
||||
val currencyTwo = "GBP - British Pound"
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -35,7 +36,7 @@ class WidgetViewModelTest {
|
||||
fun initiate_validInput_successfulResponse() {
|
||||
//GIVEN
|
||||
val appId = 123
|
||||
val pair = Pair(currencyOne,currencyTwo)
|
||||
val pair = Pair(currencyOne, currencyTwo)
|
||||
|
||||
//WHEN
|
||||
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.LifecycleOwner
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user