Merge branch 'develop' of github.com:Agorise/bitsy-wallet into develop
This commit is contained in:
commit
0092f2b225
10 changed files with 129 additions and 28 deletions
|
@ -4,6 +4,7 @@ import android.content.ComponentName
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
@ -12,6 +13,7 @@ import android.preference.PreferenceManager
|
|||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.pm.PackageInfoCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.crashlytics.android.Crashlytics
|
||||
|
@ -47,6 +49,7 @@ import java.util.*
|
|||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
/**
|
||||
* The app uses the single Activity methodology, but this activity was created so that MainActivity can extend from it.
|
||||
|
@ -127,7 +130,8 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection {
|
|||
// Configure ConnectedActivityViewModel to obtain missing equivalent values
|
||||
mConnectedActivityViewModel = ViewModelProviders.of(this).get(ConnectedActivityViewModel::class.java)
|
||||
|
||||
mConnectedActivityViewModel.observeMissingEquivalentValuesIn("usd") //TODO: Obtain this from shared preferences?
|
||||
val currency = Currency.getInstance(Locale.getDefault())
|
||||
mConnectedActivityViewModel.observeMissingEquivalentValuesIn(currency.currencyCode) //TODO: Obtain this from shared preferences?
|
||||
|
||||
// Configure UserAccountViewModel to obtain the missing account ids
|
||||
mUserAccountViewModel = ViewModelProviders.of(this).get(UserAccountViewModel::class.java)
|
||||
|
@ -174,6 +178,20 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection {
|
|||
this.handleError(it)
|
||||
})
|
||||
mCompositeDisposable.add(disposable)
|
||||
|
||||
thread {
|
||||
val info = this.packageManager.getPackageInfo(this.packageName, PackageManager.GET_ACTIVITIES)
|
||||
val versionCode = PackageInfoCompat.getLongVersionCode(info)
|
||||
val hasPurgedEquivalentValues = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, false)
|
||||
if(versionCode > 11 && !hasPurgedEquivalentValues) {
|
||||
mConnectedActivityViewModel.purgeEquivalentValues()
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit()
|
||||
.putBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, true)
|
||||
.apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,4 +13,10 @@ interface EquivalentValueDao {
|
|||
|
||||
@Query("SELECT * FROM equivalent_values")
|
||||
fun getAllEquivalentValues(): LiveData<List<EquivalentValue>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM equivalent_values WHERE symbol=:currency")
|
||||
fun getEquivalentValuesCountForCurrency(currency: String): Long
|
||||
|
||||
@Query("DELETE FROM equivalent_values WHERE value < 0")
|
||||
fun purge(): Int
|
||||
}
|
|
@ -42,8 +42,8 @@ interface TransferDetailDao {
|
|||
assets.precision AS `assetPrecision`,
|
||||
assets.symbol AS `assetSymbol`,
|
||||
assets.issuer as `assetIssuer`,
|
||||
(SELECT value FROM equivalent_values WHERE equivalent_values.transfer_id=transfers.id) AS `fiatAmount`,
|
||||
(SELECT symbol FROM equivalent_values WHERE equivalent_values.transfer_id=transfers.id) AS `fiatSymbol`
|
||||
(SELECT value FROM equivalent_values WHERE equivalent_values.transfer_id=transfers.id AND symbol=:currency) AS `fiatAmount`,
|
||||
(SELECT symbol FROM equivalent_values WHERE equivalent_values.transfer_id=transfers.id AND symbol=:currency) AS `fiatSymbol`
|
||||
FROM
|
||||
transfers
|
||||
INNER JOIN
|
||||
|
@ -51,5 +51,5 @@ interface TransferDetailDao {
|
|||
WHERE
|
||||
transfers.transfer_asset_id = assets.id
|
||||
""")
|
||||
fun getAll(userId: String): LiveData<List<TransferDetail>>
|
||||
fun getAll(userId: String, currency: String): LiveData<List<TransferDetail>>
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package cy.agorise.bitsybitshareswallet.network
|
||||
|
||||
import retrofit2.Call
|
||||
import cy.agorise.bitsybitshareswallet.models.coingecko.HistoricalPrice
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.Query
|
||||
|
@ -13,4 +13,8 @@ interface CoingeckoService {
|
|||
fun getHistoricalValueSync(@Query("id") id: String,
|
||||
@Query("date") date: String,
|
||||
@Query("localization") localization: Boolean): Call<HistoricalPrice>
|
||||
|
||||
@Headers("Content-Type: application/json")
|
||||
@GET("/api/v3/simple/supported_vs_currencies")
|
||||
fun getSupportedCurrencies(): Call<Array<String>>
|
||||
}
|
|
@ -15,4 +15,8 @@ class EquivalentValuesRepository(context: Context) {
|
|||
mEquivalentValuesDao = db?.equivalentValueDao()
|
||||
mTransfersDao = db?.transferDao()
|
||||
}
|
||||
|
||||
fun purge(): Int? {
|
||||
return mEquivalentValuesDao?.purge()
|
||||
}
|
||||
}
|
|
@ -3,24 +3,27 @@ package cy.agorise.bitsybitshareswallet.repositories
|
|||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import cy.agorise.bitsybitshareswallet.database.BitsyDatabase
|
||||
import cy.agorise.bitsybitshareswallet.database.daos.EquivalentValueDao
|
||||
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
|
||||
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetailDao
|
||||
|
||||
class TransferDetailRepository internal constructor(context: Context) {
|
||||
|
||||
private val mTransferDetailDao: TransferDetailDao
|
||||
private val mEquivalentValuesDao: EquivalentValueDao
|
||||
|
||||
init {
|
||||
val db = BitsyDatabase.getDatabase(context)
|
||||
mTransferDetailDao = db!!.transferDetailDao()
|
||||
mEquivalentValuesDao = db.equivalentValueDao()
|
||||
}
|
||||
|
||||
fun get(userId: String, transferId: String): LiveData<TransferDetail> {
|
||||
return mTransferDetailDao.get(userId, transferId)
|
||||
}
|
||||
|
||||
fun getAll(userId: String): LiveData<List<TransferDetail>> {
|
||||
return mTransferDetailDao.getAll(userId)
|
||||
fun getAll(userId: String, currency: String): LiveData<List<TransferDetail>> {
|
||||
return mTransferDetailDao.getAll(userId, currency)
|
||||
}
|
||||
|
||||
}
|
|
@ -12,9 +12,9 @@ import cy.agorise.bitsybitshareswallet.database.entities.Transfer
|
|||
import cy.agorise.bitsybitshareswallet.network.CoingeckoService
|
||||
import cy.agorise.bitsybitshareswallet.network.ServiceGenerator
|
||||
import cy.agorise.bitsybitshareswallet.utils.Constants
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
@ -77,18 +77,16 @@ class TransferRepository internal constructor(context: Context) {
|
|||
*/
|
||||
fun observeMissingEquivalentValuesIn(symbol: String) {
|
||||
compositeDisposable.add(mTransferDao.getTransfersWithMissingValueIn(symbol)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(Schedulers.io())
|
||||
.map { transfer -> obtainFiatValue(transfer, symbol) }
|
||||
.subscribe({
|
||||
Log.d(TAG,"Got equivalent value: $it")
|
||||
mEquivalentValuesDao.insert(it)
|
||||
if(it.value >= 0) mEquivalentValuesDao.insert(it)
|
||||
},{
|
||||
Log.e(TAG,"Error while trying to create a new equivalent value. Msg: ${it.message}")
|
||||
for(element in it.stackTrace){
|
||||
Log.e(TAG,"${element.className}#${element.methodName}:${element.lineNumber}")
|
||||
}
|
||||
}))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,12 +108,14 @@ class TransferRepository internal constructor(context: Context) {
|
|||
?.execute()
|
||||
var equivalentFiatValue = -1L
|
||||
if(response?.isSuccessful == true){
|
||||
val price: Double = response.body()?.market_data?.current_price?.get(symbol) ?: -1.0
|
||||
// The equivalent value is obtained by:
|
||||
// 1- Dividing the base value by 100000 (BTS native precision)
|
||||
// 2- Multiplying that BTS value by the unit price in the chosen fiat
|
||||
// 3- Multiplying the resulting value by 100 in order to express it in cents
|
||||
equivalentFiatValue = Math.round(transfer.btsValue?.div(1e5)?.times(price)?.times(100) ?: -1.0)
|
||||
val price: Double = response.body()?.market_data?.current_price?.get(symbol.toLowerCase()) ?: -1.0
|
||||
if(price > 0){
|
||||
// The equivalent value is obtained by:
|
||||
// 1- Dividing the base value by 100000 (BTS native precision)
|
||||
// 2- Multiplying that BTS value by the unit price in the chosen fiat
|
||||
// 3- Multiplying the resulting value by 100 in order to express it in cents
|
||||
equivalentFiatValue = Math.round(transfer.btsValue?.toFloat()?.div(1e5)?.times(price)?.times(100) ?: -1.0)
|
||||
}
|
||||
}else{
|
||||
Log.w(TAG,"Request was not successful. code: ${response?.code()}")
|
||||
}
|
||||
|
@ -160,4 +160,27 @@ class TransferRepository internal constructor(context: Context) {
|
|||
if(!compositeDisposable.isDisposed)
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to override a given currency if it turns out not to be supported by the API.
|
||||
* <p>
|
||||
* The CoinGecko API supports 20+ fiat currencies. So we can very easily calculate historical
|
||||
* equivalent values for those currencies. If the currency is not supported though,
|
||||
* we must fall back to USD.
|
||||
*
|
||||
* @param symbol The 3 letters symbol of the currency
|
||||
*/
|
||||
fun getSupportedCurrency(symbol: String): Observable<String> {
|
||||
return Observable.just(symbol)
|
||||
.map {
|
||||
val sg = ServiceGenerator(Constants.COINGECKO_URL)
|
||||
val response = sg.getService(CoingeckoService::class.java)
|
||||
?.getSupportedCurrencies()
|
||||
?.execute()
|
||||
if(response?.body()?.indexOf(symbol.toLowerCase()) == -1)
|
||||
"usd"
|
||||
else
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
|
@ -128,7 +128,10 @@ object Constants {
|
|||
/** Minimum time period in seconds between BitShares nodes list updates */
|
||||
const val NODES_UPDATE_PERIOD = (60 * 60).toLong() // 1 hour
|
||||
|
||||
|
||||
/** Because of a bug in pre-version code 11 releases, some entries in the equivalent values
|
||||
* table were invalid. We'll be performing a purge at version code 12, but we only want to do
|
||||
* it once. After this, we record this in shared preferences using this key */
|
||||
const val KEY_HAS_PURGED_EQUIVALENT_VALUES = "key_has_purged_equivalent_values"
|
||||
/////////////////////// Crashlytics custom keys ///////////////////////
|
||||
|
||||
/** Key used to add the last visited fragment name to the Crashlytics report */
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
package cy.agorise.bitsybitshareswallet.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import cy.agorise.bitsybitshareswallet.database.BitsyDatabase
|
||||
import cy.agorise.bitsybitshareswallet.repositories.EquivalentValuesRepository
|
||||
import cy.agorise.bitsybitshareswallet.repositories.NodeRepository
|
||||
import cy.agorise.bitsybitshareswallet.repositories.TransferRepository
|
||||
import cy.agorise.graphenej.network.FullNode
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
class ConnectedActivityViewModel(application: Application) : AndroidViewModel(application) {
|
||||
companion object {
|
||||
val TAG = "ConnectedActivityVM"
|
||||
}
|
||||
private var mTransfersRepository = TransferRepository(application)
|
||||
|
||||
private var mEquivalentValuesRep = EquivalentValuesRepository(application)
|
||||
private val mNodeRepository: NodeRepository
|
||||
|
||||
init {
|
||||
|
@ -18,7 +24,17 @@ class ConnectedActivityViewModel(application: Application) : AndroidViewModel(ap
|
|||
}
|
||||
|
||||
fun observeMissingEquivalentValuesIn(symbol: String) {
|
||||
mTransfersRepository.observeMissingEquivalentValuesIn(symbol)
|
||||
mTransfersRepository.getSupportedCurrency(symbol)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe({
|
||||
currency -> mTransfersRepository.observeMissingEquivalentValuesIn(currency)
|
||||
},{
|
||||
Log.e(TAG,"Error while trying to subscribe to missing equivalent values observer. Msg: ${it.message}")
|
||||
for(element in it.stackTrace){
|
||||
Log.e(TAG,"${element.className}#${element.methodName}:${element.lineNumber}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun updateNodeLatencies(nodes: List<FullNode>) {
|
||||
|
@ -29,4 +45,8 @@ class ConnectedActivityViewModel(application: Application) : AndroidViewModel(ap
|
|||
super.onCleared()
|
||||
mTransfersRepository.onCleared()
|
||||
}
|
||||
|
||||
fun purgeEquivalentValues(): Int? {
|
||||
return mEquivalentValuesRep.purge()
|
||||
}
|
||||
}
|
|
@ -1,17 +1,25 @@
|
|||
package cy.agorise.bitsybitshareswallet.viewmodels
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.*
|
||||
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
|
||||
import cy.agorise.bitsybitshareswallet.models.FilterOptions
|
||||
import cy.agorise.bitsybitshareswallet.repositories.TransferDetailRepository
|
||||
import cy.agorise.bitsybitshareswallet.repositories.TransferRepository
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
||||
class TransactionsViewModel(application: Application) : AndroidViewModel(application) {
|
||||
companion object {
|
||||
val TAG = "TransactionsViewModel"
|
||||
}
|
||||
private var mRepository = TransferDetailRepository(application)
|
||||
private var mTransfersRepository = TransferRepository(application)
|
||||
|
||||
/**
|
||||
* [FilterOptions] used to filter the list of [TransferDetail] taken from the database
|
||||
|
@ -35,13 +43,25 @@ class TransactionsViewModel(application: Application) : AndroidViewModel(applica
|
|||
}
|
||||
|
||||
internal fun getFilteredTransactions(userId: String): LiveData<List<TransferDetail>> {
|
||||
transactions = mRepository.getAll(userId)
|
||||
val currency = Currency.getInstance(Locale.getDefault())
|
||||
mTransfersRepository.getSupportedCurrency(currency.currencyCode)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
Log.d(TAG,"Looking for currency with code: ${it}")
|
||||
transactions = mRepository.getAll(userId, it)
|
||||
|
||||
filteredTransactions.addSource(transactions) { transactions ->
|
||||
viewModelScope.launch {
|
||||
filteredTransactions.value = filter(transactions, mFilterOptions)
|
||||
}
|
||||
}
|
||||
filteredTransactions.addSource(transactions) { transactions ->
|
||||
viewModelScope.launch {
|
||||
filteredTransactions.value = filter(transactions, mFilterOptions)
|
||||
}
|
||||
}
|
||||
},{
|
||||
Log.e(TAG,"Error while trying to obtain a filtered list of transactions. Msg: ${it.message}")
|
||||
for(element in it.stackTrace){
|
||||
Log.e(ConnectedActivityViewModel.TAG,"${element.className}#${element.methodName}:${element.lineNumber}")
|
||||
}
|
||||
})
|
||||
|
||||
return filteredTransactions
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue