From 14d782aa5f40ca20113fa35a6d7801a0aa47a4da Mon Sep 17 00:00:00 2001 From: Ebenezer Ackon Date: Sun, 15 Apr 2018 22:15:53 -0400 Subject: [PATCH 1/2] Add rxKotlin version 2.2.0 --- app/build.gradle | 7 +++++++ etherscanapi/build.gradle | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9426f64..781cb24 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,6 +25,13 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + + /** + Because RxAndroid releases are few and far between, it is recommended you also + explicitly depend on RxJava's latest version for bug fixes and new features. + */ + implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' + implementation 'io.reactivex.rxjava2:rxkotlin:2.2.0' // kotlin implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" diff --git a/etherscanapi/build.gradle b/etherscanapi/build.gradle index c8429b9..c591856 100644 --- a/etherscanapi/build.gradle +++ b/etherscanapi/build.gradle @@ -28,10 +28,10 @@ dependencies { /** Because RxAndroid releases are few and far between, it is recommended you also - explicitly depend on RxJava's latest version for bug fixes and new features. + explicitly depend on RxKotlin's latest version for bug fixes and new features. */ implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' - implementation 'io.reactivex.rxjava2:rxjava:2.1.9' + implementation 'io.reactivex.rxjava2:rxkotlin:2.2.0' // gson implementation 'com.google.code.gson:gson:2.8.2' From 5cdee79783756aa9bec276a818690a77947921e5 Mon Sep 17 00:00:00 2001 From: Ebenezer Ackon Date: Sun, 15 Apr 2018 22:18:41 -0400 Subject: [PATCH 2/2] keep reactive stream open by returning Singles --- .../etherscan/helloetherescan/MainActivity.kt | 48 +++---- .../src/main/java/jfyg/account/Account.kt | 72 ++++++---- .../main/java/jfyg/account/AccountContract.kt | 15 +- .../main/java/jfyg/queries/AccountQueries.kt | 22 +-- .../main/java/jfyg/queries/QueryMediator.kt | 129 +++++------------- .../src/main/java/jfyg/queries/StatQueries.kt | 10 +- etherscanapi/src/main/java/jfyg/stat/Stat.kt | 17 +-- .../src/main/java/jfyg/stat/StatContract.kt | 18 +-- 8 files changed, 130 insertions(+), 201 deletions(-) diff --git a/app/src/main/java/jfyg/etherscan/helloetherescan/MainActivity.kt b/app/src/main/java/jfyg/etherscan/helloetherescan/MainActivity.kt index b394745..059dd89 100644 --- a/app/src/main/java/jfyg/etherscan/helloetherescan/MainActivity.kt +++ b/app/src/main/java/jfyg/etherscan/helloetherescan/MainActivity.kt @@ -3,6 +3,8 @@ package jfyg.etherscan.helloetherescan import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.util.Log +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.rxkotlin.subscribeBy import jfyg.account.Account import jfyg.stat.Stat import kotlinx.android.synthetic.main.activity_main.* @@ -16,41 +18,27 @@ class MainActivity : AppCompatActivity() { setContentView(R.layout.activity_main) setSupportActionBar(toolbar) - //************************************************ Used To Test Library + //************************************************ Used To Test Singles returned from etherscanapi Module val stat = Stat() val account = Account() + fab.setOnClickListener { - //stat - Log.d(TAG, "The Stat Status is ${stat.getNetworkStatus()}") - Log.d(TAG, "The Stat Message is ${stat.getNetworkMessage()}") - Log.d(TAG, "The current price of Ether in Btc: ${stat.getLastPriceInBtc()}") - Log.d(TAG, "Timestamp price in Btc: ${stat.getBtcTimestamp()}") - Log.d(TAG, "Timestamp price in Ether: ${stat.getEthTimestamp()}") - Log.d(TAG, "The current price of Ether in Usd: ${stat.getLastPriceInUsd()}") - Log.d(TAG, "The total supply of Ether: ${stat.getTotalSupply()}") - Log.d(TAG, "The total supply of Ether in Wei: ${stat.getTotalSupplyInWei()}") - - //account - Log.d(TAG, "The Account Status is: ${account.getNetworkStatus()}") - Log.d(TAG, "The Account Message is: ${account.getNetworkMessage()}") - Log.d(TAG, "The Account Balance is: ${account.getBalance("0x82e4499D4b2A669831a3881d61BB24f7b620c61a")}") - Log.d(TAG, "The Account(1) Balance is: ${account.getMultiBalance(threeAddresses())?.get(1)?.balance}") - Log.d(TAG, "The Account Size of Blocks is: ${account.getBlocks("0x82e4499D4b2A669831a3881d61BB24f7b620c61a")?.size}") - Log.d(TAG, "The Account Size of Transactions is: ${account.getTransactions("0x82e4499D4b2A669831a3881d61BB24f7b620c61a")?.size}") - Log.d(TAG, "The Account Size of Internal Transactions is: ${account.getInternalTransactions("0x2c1ba59d6f58433fb1eaee7d20b26ed83bda51a3")?.size}") - - //transactions - } - } + //stat test + stat.getLastPriceInBtc()?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeBy { + Log.d(TAG, "The current price of Ether in Btc: $it") + } - fun threeAddresses(): ArrayList { - val address = ArrayList() - address.add("0x82e4499D4b2A669831a3881d61BB24f7b620c61a") - address.add("0x63a9975ba31b0b9626b34300f7f627147df1f526") - address.add("0x198ef1ec325a96cc354c7266a038be8b5c558f67") - return address + //account test + account.getTransactions("0x2c1ba59d6f58433fb1eaee7d20b26ed83bda51a3")?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribeBy { + Log.d(TAG, "The Account Size of Transactions is: ${it.size}") + } + + //transaction test + } } -} \ No newline at end of file +} diff --git a/etherscanapi/src/main/java/jfyg/account/Account.kt b/etherscanapi/src/main/java/jfyg/account/Account.kt index 603e6f3..f1e1620 100644 --- a/etherscanapi/src/main/java/jfyg/account/Account.kt +++ b/etherscanapi/src/main/java/jfyg/account/Account.kt @@ -1,5 +1,6 @@ package jfyg.account +import io.reactivex.Single import jfyg.model.Balances import jfyg.model.Blocks import jfyg.model.Transactions @@ -10,38 +11,49 @@ import jfyg.utils.QueryUtils class Account : AccountContract { private val query = QueryMediator() - private val genericNetworkQuery = query.accountBalance("account", "balance", - "0x82e4499D4b2A669831a3881d61BB24f7b620c61a", "latest") + private val genericNetworkQuery = query.accountBalance("account", + "balance", + "0x82e4499D4b2A669831a3881d61BB24f7b620c61a", + "latest") private val queryUtil = QueryUtils() - override fun getBalance(account: String?): Double? = - query.accountBalance("account", "balance", - account, "latest").let { query.fetchAccountBalance()?.result?.toDouble() } - - - override fun getMultiBalance(accounts: ArrayList?): ArrayList? = - query.accountMultiBalance("account", "balancemulti", - queryUtil.retrieveAccounts(accounts), "latest").let { query.fetchAccountMultiBalance()?.result } - - //todo #29 - override fun getBlocks(account: String?): ArrayList? = - query.accountBlock("account", "getminedblocks", - account, "blocks").let { query.fetchAccountBlock()?.result } - - //todo #29 - override fun getTransactions(account: String?): ArrayList? = - query.accountTransactions("account", "txlist", - account, "0", "99999999", - "asc").let { query.fetchAccountTransaction()?.result } - - override fun getInternalTransactions(account: String?): ArrayList? = - query.accountInternalTransactions("account", "txlistinternal", - account, "0", "99999999", - "asc").let { query.fetchAccountInternalTransaction()?.result } - - override fun getNetworkStatus(): String? = genericNetworkQuery.let { query.fetchAccountBalance()?.status } - - override fun getNetworkMessage(): String? = genericNetworkQuery.let { query.fetchAccountBalance()?.message } + override fun getBalance(account: String?): Single? = + query.accountBalance("account", + "balance", + account, + "latest")?.map { it.result?.toDouble() } + + override fun getMultiBalance(accounts: ArrayList?): Single>? = + query.accountMultiBalance("account", + "balancemulti", + queryUtil.retrieveAccounts(accounts), + "latest")?.map { it.result } + + override fun getBlocks(account: String?): Single>? = + query.accountBlock("account", + "getminedblocks", + account, + "blocks")?.map { it.result } + + override fun getTransactions(account: String?): Single>? = + query.accountTransactions("account", + "txlist", + account, + "0", + "99999999", + "asc")?.map { it.result } + + override fun getInternalTransactions(account: String?): Single>? = + query.accountInternalTransactions("account", + "txlistinternal", + account, + "0", + "99999999", + "asc")?.map { it.result } + + override fun getNetworkStatus(): Single? = genericNetworkQuery?.map { it.status } + + override fun getNetworkMessage(): Single? = genericNetworkQuery?.map { it.message } } \ No newline at end of file diff --git a/etherscanapi/src/main/java/jfyg/account/AccountContract.kt b/etherscanapi/src/main/java/jfyg/account/AccountContract.kt index 4f186a7..e245a32 100644 --- a/etherscanapi/src/main/java/jfyg/account/AccountContract.kt +++ b/etherscanapi/src/main/java/jfyg/account/AccountContract.kt @@ -1,5 +1,6 @@ package jfyg.account +import io.reactivex.Single import jfyg.model.Balances import jfyg.model.Blocks import jfyg.model.Transactions @@ -10,36 +11,36 @@ internal interface AccountContract { /** * Return network status */ - fun getNetworkStatus(): String? + fun getNetworkStatus(): Single? /** * Return network message */ - fun getNetworkMessage(): String? + fun getNetworkMessage(): Single? /** * Return account balance */ - fun getBalance(account: String?): Double? + fun getBalance(account: String?): Single? /** * Return balances of multiple accounts separated by commas */ - fun getMultiBalance(accounts: ArrayList?): ArrayList? + fun getMultiBalance(accounts: ArrayList?): Single>? /** * Get list of blocks mined by address */ - fun getBlocks(account: String?): ArrayList? + fun getBlocks(account: String?): Single>? /** * Get a list of 'Normal' Transactions By Address */ - fun getTransactions(account: String?): ArrayList? + fun getTransactions(account: String?): Single>? /** * Get a list of 'Internal' Transactions by Address */ - fun getInternalTransactions(account: String?): ArrayList? + fun getInternalTransactions(account: String?): Single>? } \ No newline at end of file diff --git a/etherscanapi/src/main/java/jfyg/queries/AccountQueries.kt b/etherscanapi/src/main/java/jfyg/queries/AccountQueries.kt index 20e7576..82dc843 100644 --- a/etherscanapi/src/main/java/jfyg/queries/AccountQueries.kt +++ b/etherscanapi/src/main/java/jfyg/queries/AccountQueries.kt @@ -1,6 +1,6 @@ package jfyg.queries -import io.reactivex.disposables.Disposable +import io.reactivex.Single import jfyg.response.account.AccountBalanceResponse import jfyg.response.account.AccountBlockResponse import jfyg.response.account.AccountInternalTransactionResponse @@ -15,7 +15,7 @@ internal interface AccountQueries { fun accountBalance(module: String?, action: String?, address: String?, - tag: String?): Disposable? + tag: String?): Single? /** * Get Ether Balance for multiple Addresses in a single call @@ -23,7 +23,7 @@ internal interface AccountQueries { fun accountMultiBalance(module: String?, action: String?, address: String?, - tag: String?): Disposable? + tag: String?): Single? /** * Get list of blocks mined by address @@ -31,7 +31,7 @@ internal interface AccountQueries { fun accountBlock(module: String?, action: String?, address: String?, - blocktype: String?): Disposable? + blocktype: String?): Single? /** * Get a list of 'Normal' transactions by address @@ -41,7 +41,7 @@ internal interface AccountQueries { address: String?, startblock: String?, endblock: String?, - sort: String?): Disposable? + sort: String?): Single? /** * Get a list of 'Internal' transactions by address @@ -51,16 +51,6 @@ internal interface AccountQueries { address: String?, startblock: String?, endblock: String?, - sort: String?): Disposable? - - fun handleResponse(response: AccountBalanceResponse) - - fun handleResponse(response: AccountMultiBalanceResponse) - - fun handleResponse(response: AccountBlockResponse) - - fun handleResponse(response: AccountTransactionResponse) - - fun handleResponse(response: AccountInternalTransactionResponse) + sort: String?): Single? } \ No newline at end of file diff --git a/etherscanapi/src/main/java/jfyg/queries/QueryMediator.kt b/etherscanapi/src/main/java/jfyg/queries/QueryMediator.kt index be213d6..8434243 100644 --- a/etherscanapi/src/main/java/jfyg/queries/QueryMediator.kt +++ b/etherscanapi/src/main/java/jfyg/queries/QueryMediator.kt @@ -1,8 +1,6 @@ package jfyg.queries -import android.util.Log -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.Disposable +import io.reactivex.Single import jfyg.ApiKey import jfyg.network.RestClient import jfyg.response.account.AccountBalanceResponse @@ -16,108 +14,49 @@ import jfyg.response.stat.StatSupplyResponse /** * A mediator between the responses and errors that come from every query */ -internal class QueryMediator : AccountQueries, StatQueries { //todo #36 - private val TAG = javaClass.name +internal class QueryMediator : AccountQueries, StatQueries { - private var statPriceInfo = StatPriceResponse() - private var statSupplyInfo = StatSupplyResponse() - private var accountBalanceInfo = AccountBalanceResponse() - private var accountMultiBalanceInfo = AccountMultiBalanceResponse() - private var accountBlockInfo = AccountBlockResponse() - private var accountTransactionInfo = AccountTransactionResponse() - private var accountInternalTransactionInfo = AccountInternalTransactionResponse() - - - override fun accountBalance(module: String?, action: String?, address: String?, tag: String?): Disposable? = + override fun accountBalance(module: String?, + action: String?, + address: String?, + tag: String?): Single? = RestClient().getQuery().getAccountBalance(module, action, address, tag, ApiKey.takeOff.callApiKey()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - - override fun accountMultiBalance(module: String?, action: String?, address: String?, tag: String?): Disposable? = + override fun accountMultiBalance(module: String?, + action: String?, + address: String?, + tag: String?): Single? = RestClient().getQuery().getAccountMultiBalance(module, action, address, tag, ApiKey.takeOff.callApiKey()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - - override fun accountBlock(module: String?, action: String?, address: String?, blocktype: String?): Disposable? = + override fun accountBlock(module: String?, + action: String?, + address: String?, + blocktype: String?): Single? = RestClient().getQuery().getAccountBlock(module, action, address, blocktype, ApiKey.takeOff.callApiKey()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - - override fun accountTransactions(module: String?, action: String?, address: String?, startblock: String?, - endblock: String?, sort: String?): Disposable? = - RestClient().getQuery().getAccountTransactions(module, action, address, startblock, endblock, sort, - ApiKey.takeOff.callApiKey()) - - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - override fun accountInternalTransactions(module: String?, action: String?, address: String?, startblock: String?, - endblock: String?, sort: String?): Disposable? = - RestClient().getQuery().getAccountInternalTransactions(module, action, address, startblock, endblock, sort, - ApiKey.takeOff.callApiKey()) - - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - - override fun statPrice(module: String, action: String): Disposable? = + override fun accountTransactions(module: String?, + action: String?, + address: String?, + startblock: String?, + endblock: String?, + sort: String?): Single? = + RestClient().getQuery().getAccountTransactions(module, action, address, startblock, endblock, sort, ApiKey.takeOff.callApiKey()) + + override fun accountInternalTransactions(module: String?, + action: String?, + address: String?, + startblock: String?, + endblock: String?, + sort: String?): Single? = + RestClient().getQuery().getAccountInternalTransactions(module, action, address, startblock, endblock, sort, ApiKey.takeOff.callApiKey()) + + override fun statPrice(module: String, + action: String): Single? = RestClient().getQuery().getStat(module, action, ApiKey.takeOff.callApiKey()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - override fun statSupply(module: String, action: String): Disposable? = + override fun statSupply(module: String, + action: String): Single? = RestClient().getQuery().getStatSupply(module, action, ApiKey.takeOff.callApiKey()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(this::handleResponse, this::handleError) - - - override fun handleResponse(response: AccountBalanceResponse) { - accountBalanceInfo = response - } - - override fun handleResponse(response: AccountBlockResponse) { - accountBlockInfo = response - } - - override fun handleResponse(response: AccountTransactionResponse) { - accountTransactionInfo = response - } - - override fun handleResponse(response: StatPriceResponse) { - statPriceInfo = response - } - - override fun handleResponse(response: StatSupplyResponse) { - statSupplyInfo = response - } - - override fun handleResponse(response: AccountMultiBalanceResponse) { - accountMultiBalanceInfo = response - } - - override fun handleResponse(response: AccountInternalTransactionResponse) { - accountInternalTransactionInfo = response - } - - private fun handleError(error: Throwable) { - Log.d(TAG, "The error ${error.message}") - } - - fun fetchStatPrice(): StatPriceResponse? = statPriceInfo - fun fetchStatSupply(): StatSupplyResponse? = statSupplyInfo - fun fetchAccountBalance(): AccountBalanceResponse? = accountBalanceInfo - fun fetchAccountMultiBalance(): AccountMultiBalanceResponse? = accountMultiBalanceInfo - fun fetchAccountBlock(): AccountBlockResponse? = accountBlockInfo - fun fetchAccountTransaction(): AccountTransactionResponse? = accountTransactionInfo - fun fetchAccountInternalTransaction(): AccountInternalTransactionResponse? = accountInternalTransactionInfo - } \ No newline at end of file diff --git a/etherscanapi/src/main/java/jfyg/queries/StatQueries.kt b/etherscanapi/src/main/java/jfyg/queries/StatQueries.kt index c243ff6..50b7c01 100644 --- a/etherscanapi/src/main/java/jfyg/queries/StatQueries.kt +++ b/etherscanapi/src/main/java/jfyg/queries/StatQueries.kt @@ -1,6 +1,6 @@ package jfyg.queries -import io.reactivex.disposables.Disposable +import io.reactivex.Single import jfyg.response.stat.StatPriceResponse import jfyg.response.stat.StatSupplyResponse @@ -9,15 +9,11 @@ internal interface StatQueries { /** * Get Ether last price */ - fun statPrice(module: String, action: String): Disposable? + fun statPrice(module: String, action: String): Single? /** * Get total supply of Ether */ - fun statSupply(module: String, action: String): Disposable? - - fun handleResponse(response: StatPriceResponse) - - fun handleResponse(response: StatSupplyResponse) + fun statSupply(module: String, action: String): Single? } \ No newline at end of file diff --git a/etherscanapi/src/main/java/jfyg/stat/Stat.kt b/etherscanapi/src/main/java/jfyg/stat/Stat.kt index c79e888..a7b9370 100644 --- a/etherscanapi/src/main/java/jfyg/stat/Stat.kt +++ b/etherscanapi/src/main/java/jfyg/stat/Stat.kt @@ -1,5 +1,6 @@ package jfyg.stat +import io.reactivex.Single import jfyg.queries.QueryMediator class Stat : StatContract { @@ -10,20 +11,20 @@ class Stat : StatContract { private val wei = 1000000000000000000 // 1 Ether is 1000000000000000000 Wei - override fun getTotalSupply(): Double? = supplyQuery.let { query.fetchStatSupply()?.result?.toDouble() } + override fun getTotalSupply(): Single? = supplyQuery?.map { it.result?.toDouble() } - override fun getTotalSupplyInWei(): Double? = supplyQuery.let { query.fetchStatSupply()?.result?.toDouble()?.div(wei) } + override fun getTotalSupplyInWei(): Single? = supplyQuery?.map { it.result?.toDouble()?.div(wei) } - override fun getLastPriceInUsd(): Float? = priceQuery.let { query.fetchStatPrice()?.result?.ethUsd?.toFloat() } + override fun getLastPriceInUsd(): Single? = priceQuery?.map { it.result?.ethUsd?.toFloat() } - override fun getEthTimestamp(): Long? = priceQuery.let { query.fetchStatPrice()?.result?.ethUsdTimestamp?.toLong() } + override fun getEthTimestamp(): Single? = priceQuery?.map { it.result?.ethUsdTimestamp?.toLong() } - override fun getLastPriceInBtc(): Float? = priceQuery.let { query.fetchStatPrice()?.result?.ethBtc?.toFloat() } + override fun getLastPriceInBtc(): Single? = priceQuery?.map { it.result?.ethBtcTimestamp?.toFloat() } - override fun getBtcTimestamp(): Long? = priceQuery.let { query.fetchStatPrice()?.result?.ethBtcTimestamp?.toLong() } + override fun getBtcTimestamp(): Single? = priceQuery?.map { it.result?.ethBtcTimestamp?.toLong() } - override fun getNetworkStatus(): String? = priceQuery.let { query.fetchStatPrice()?.status } + override fun getNetworkStatus(): Single? = priceQuery?.map { it.status } - override fun getNetworkMessage(): String? = priceQuery.let { query.fetchStatPrice()?.message } + override fun getNetworkMessage(): Single? = priceQuery?.map { it.message } } \ No newline at end of file diff --git a/etherscanapi/src/main/java/jfyg/stat/StatContract.kt b/etherscanapi/src/main/java/jfyg/stat/StatContract.kt index 373cf12..4313096 100644 --- a/etherscanapi/src/main/java/jfyg/stat/StatContract.kt +++ b/etherscanapi/src/main/java/jfyg/stat/StatContract.kt @@ -1,45 +1,47 @@ package jfyg.stat +import io.reactivex.Single + internal interface StatContract { /** * Return total supply of Ether */ - fun getTotalSupply(): Double? + fun getTotalSupply(): Single? /** * Return total supply of Ether in Wei */ - fun getTotalSupplyInWei(): Double? + fun getTotalSupplyInWei(): Single? /** * Return last price of Ether in Btc */ - fun getLastPriceInBtc(): Float? + fun getLastPriceInBtc(): Single? /** * Return timestamp */ - fun getBtcTimestamp(): Long? + fun getBtcTimestamp(): Single? /** * Return last price of Ether in Usd */ - fun getLastPriceInUsd(): Float? + fun getLastPriceInUsd(): Single? /** * Return timestamp */ - fun getEthTimestamp(): Long? + fun getEthTimestamp(): Single? /** * Return network status */ - fun getNetworkStatus(): String? + fun getNetworkStatus(): Single? /** * Return network message */ - fun getNetworkMessage(): String? + fun getNetworkMessage(): Single? } \ No newline at end of file