From 81531cc8b671d7d40763ffcd80bf6151f400277e Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Fri, 11 Jan 2019 13:46:50 -0600 Subject: [PATCH] Add functionality to ImportBrainkeyFragment's 'View Network Status' to show the nodes dialog. Most of it was copied fom the same dialog already implemented in the Settings screen. --- .../fragments/ImportBrainkeyFragment.kt | 108 ++++++++++++++++++ .../fragments/SettingsFragment.kt | 7 +- 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ImportBrainkeyFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ImportBrainkeyFragment.kt index 69a30cd..a55f6d1 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ImportBrainkeyFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ImportBrainkeyFragment.kt @@ -1,6 +1,9 @@ package cy.agorise.bitsybitshareswallet.fragments +import android.content.ComponentName import android.os.Bundle +import android.os.Handler +import android.os.IBinder import android.util.Log import android.view.LayoutInflater import android.view.View @@ -8,24 +11,34 @@ import android.view.ViewGroup import androidx.appcompat.widget.Toolbar import androidx.navigation.Navigation import com.afollestad.materialdialogs.MaterialDialog +import com.afollestad.materialdialogs.list.customListAdapter import com.afollestad.materialdialogs.list.listItemsSingleChoice import com.jakewharton.rxbinding3.widget.textChanges +import cy.agorise.bitsybitshareswallet.BuildConfig import cy.agorise.bitsybitshareswallet.R +import cy.agorise.bitsybitshareswallet.adapters.FullNodesAdapter import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.toast import cy.agorise.graphenej.* import cy.agorise.graphenej.api.ConnectionStatusUpdate import cy.agorise.graphenej.api.calls.GetAccounts +import cy.agorise.graphenej.api.calls.GetDynamicGlobalProperties import cy.agorise.graphenej.api.calls.GetKeyReferences import cy.agorise.graphenej.models.AccountProperties +import cy.agorise.graphenej.models.DynamicGlobalProperties import cy.agorise.graphenej.models.JsonRpcResponse +import cy.agorise.graphenej.network.FullNode +import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.fragment_import_brainkey.* import org.bitcoinj.core.ECKey +import java.text.NumberFormat import java.util.ArrayList import java.util.concurrent.TimeUnit class ImportBrainkeyFragment : BaseAccountFragment() { + companion object { private const val TAG = "ImportBrainkeyActivity" } @@ -48,6 +61,15 @@ class ImportBrainkeyFragment : BaseAccountFragment() { private var isPINConfirmationValid = false private var isBrainKeyValid = false + // Dialog displaying the list of nodes and their latencies + private var mNodesDialog: MaterialDialog? = null + + /** Adapter that holds the FullNode list used in the Bitshares nodes modal */ + private var mNodesAdapter: FullNodesAdapter? = null + + /** Handler that will be used to make recurrent calls to get the latest BitShares block number*/ + private val mHandler = Handler() + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { // Remove up navigation icon from the toolbar val toolbar: Toolbar? = activity?.findViewById(R.id.toolbar) @@ -93,6 +115,32 @@ class ImportBrainkeyFragment : BaseAccountFragment() { btnCreate.setOnClickListener ( Navigation.createNavigateOnClickListener(R.id.create_account_action) ) + + tvNetworkStatus.setOnClickListener { v -> + if (mNetworkService != null) { + // PublishSubject used to announce full node latencies updates + val fullNodePublishSubject = mNetworkService!!.nodeLatencyObservable + fullNodePublishSubject?.observeOn(AndroidSchedulers.mainThread())?.subscribe(nodeLatencyObserver) + + val fullNodes = mNetworkService!!.nodes + + mNodesAdapter = FullNodesAdapter(v.context) + mNodesAdapter?.add(fullNodes) + + mNodesDialog = MaterialDialog(v.context) + .title(text = String.format("%s v%s", getString(R.string.app_name), BuildConfig.VERSION_NAME)) + .message(text = getString(R.string.title__bitshares_nodes_dialog, "-------")) + .customListAdapter(mNodesAdapter as FullNodesAdapter) + .negativeButton(android.R.string.ok) { + mHandler.removeCallbacks(mRequestDynamicGlobalPropertiesTask) + } + + mNodesDialog?.show() + + // Registering a recurrent task used to poll for dynamic global properties requests + mHandler.post(mRequestDynamicGlobalPropertiesTask) + } + } } private fun validatePIN() { @@ -196,6 +244,12 @@ class ImportBrainkeyFragment : BaseAccountFragment() { handleBrainKeyAccountReferences(response.result) } else if (response.id == getAccountsRequestId) { handleAccountProperties(response.result) + } else if (response.result is DynamicGlobalProperties) { + val dynamicGlobalProperties = response.result as DynamicGlobalProperties + if (mNodesDialog != null && mNodesDialog?.isShowing == true) { + val blockNumber = NumberFormat.getInstance().format(dynamicGlobalProperties.head_block_number) + mNodesDialog?.message(text = getString(R.string.title__bitshares_nodes_dialog, blockNumber)) + } } } @@ -281,4 +335,58 @@ class ImportBrainkeyFragment : BaseAccountFragment() { } } } + + /** + * Observer used to be notified about node latency measurement updates. + */ + private val nodeLatencyObserver = object : Observer { + override fun onSubscribe(d: Disposable) { + mDisposables.add(d) + } + + override fun onNext(fullNode: FullNode) { + if (!fullNode.isRemoved) + mNodesAdapter?.add(fullNode) + else + mNodesAdapter?.remove(fullNode) + } + + override fun onError(e: Throwable) { + Log.e(TAG, "nodeLatencyObserver.onError.Msg: " + e.message) + } + + override fun onComplete() {} + } + + /** + * Task used to obtain frequent updates on the global dynamic properties object + */ + private val mRequestDynamicGlobalPropertiesTask = object : Runnable { + override fun run() { + if (mNetworkService != null) { + if (mNetworkService?.isConnected == true) { + mNetworkService?.sendMessage(GetDynamicGlobalProperties(), GetDynamicGlobalProperties.REQUIRED_API) + } else { + Log.d(TAG, "NetworkService exists but is not connected") + } + } else { + Log.d(TAG, "NetworkService reference is null") + } + mHandler.postDelayed(this, Constants.BLOCK_PERIOD) + } + } + + override fun onServiceDisconnected(name: ComponentName?) { + super.onServiceDisconnected(name) + + tvNetworkStatus.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, + resources.getDrawable(R.drawable.ic_disconnected, null), null) + } + + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + super.onServiceConnected(name, service) + + tvNetworkStatus.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, + resources.getDrawable(R.drawable.ic_connected, null), null) + } } \ No newline at end of file diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt index 083515c..db36227 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/SettingsFragment.kt @@ -35,7 +35,10 @@ import kotlinx.android.synthetic.main.fragment_settings.* import java.text.NumberFormat class SettingsFragment : Fragment(), ServiceConnection { - private val TAG = this.javaClass.simpleName + + companion object { + private const val TAG = "SettingsFragment" + } private var mDisposables = CompositeDisposable() @@ -77,7 +80,7 @@ class SettingsFragment : Fragment(), ServiceConnection { val fullNodes = mNetworkService!!.nodes nodesAdapter = FullNodesAdapter(v.context) - nodesAdapter!!.add(fullNodes) + nodesAdapter?.add(fullNodes) mNodesDialog = MaterialDialog(v.context) .title(text = String.format("%s v%s", getString(R.string.app_name), BuildConfig.VERSION_NAME))