Created ConnectedFragment, that encapsulates the repeated code which encapsulates the repeated code Fragmets that connect to the NetworkService use. Simplified SendTransactionFragment by extending the newly created ConnectedFragment.

This commit is contained in:
Severiano Jaramillo 2019-01-04 13:13:55 -06:00
parent 10014263d7
commit 4e64b10014
3 changed files with 124 additions and 71 deletions

View file

@ -27,7 +27,6 @@ import org.bitcoinj.core.ECKey
import java.util.ArrayList import java.util.ArrayList
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
// TODO Add method to load the 20? most important assets
// TODO add progress bar or something while the user waits for the import response from the node // TODO add progress bar or something while the user waits for the import response from the node
class ImportBrainkeyActivity : ConnectedActivity() { class ImportBrainkeyActivity : ConnectedActivity() {

View file

@ -0,0 +1,106 @@
package cy.agorise.bitsybitshareswallet.fragments
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import cy.agorise.graphenej.api.ConnectionStatusUpdate
import cy.agorise.graphenej.api.android.NetworkService
import cy.agorise.graphenej.api.android.RxBus
import cy.agorise.graphenej.models.JsonRpcResponse
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
/**
* Base fragment that defines the methods and variables commonly used in all fragments that directly connect and
* talk to the BitShares nodes through graphenej's NetworkService
*/
abstract class ConnectedFragment: Fragment(), ServiceConnection {
companion object {
private const val TAG = "ConnectedFragment"
}
/** Network service connection */
protected var mNetworkService: NetworkService? = null
/** Flag used to keep track of the NetworkService binding state */
private var mShouldUnbindNetwork: Boolean = false
/** Keeps track of all RxJava disposables, to make sure they are all disposed when the fragment is destroyed */
protected var mDisposables = CompositeDisposable()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Connect to the RxBus, which receives events from the NetworkService
mDisposables.add(
RxBus.getBusInstance()
.asFlowable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { handleIncomingMessage(it) }
)
}
private fun handleIncomingMessage(message: Any?) {
if (message is JsonRpcResponse<*>) {
// Generic processing taken care by subclasses
handleJsonRpcResponse(message)
} else if (message is ConnectionStatusUpdate) {
// Generic processing taken care by subclasses
handleConnectionStatusUpdate(message)
}
}
override fun onResume() {
super.onResume()
val intent = Intent(context, NetworkService::class.java)
if (context?.bindService(intent, this, Context.BIND_AUTO_CREATE) == true) {
mShouldUnbindNetwork = true
} else {
Log.e(TAG, "Binding to the network service failed.")
}
}
override fun onPause() {
super.onPause()
// Unbinding from network service
if (mShouldUnbindNetwork) {
context?.unbindService(this)
mShouldUnbindNetwork = false
}
}
override fun onDestroy() {
super.onDestroy()
if (!mDisposables.isDisposed) mDisposables.dispose()
}
override fun onServiceDisconnected(name: ComponentName?) { }
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
val binder = service as NetworkService.LocalBinder
mNetworkService = binder.service
}
/**
* Method to be implemented by all subclasses in order to be notified of JSON-RPC responses.
* @param response
*/
abstract fun handleJsonRpcResponse(response: JsonRpcResponse<*>)
/**
* Method to be implemented by all subclasses in order to be notified of connection status updates
* @param connectionStatusUpdate
*/
abstract fun handleConnectionStatusUpdate(connectionStatusUpdate: ConnectionStatusUpdate)
}

View file

@ -1,13 +1,8 @@
package cy.agorise.bitsybitshareswallet.fragments package cy.agorise.bitsybitshareswallet.fragments
import android.Manifest import android.Manifest
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.os.IBinder
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.util.Log import android.util.Log
import android.view.* import android.view.*
@ -15,7 +10,6 @@ import android.widget.AdapterView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
@ -32,8 +26,6 @@ import cy.agorise.bitsybitshareswallet.utils.*
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
import cy.agorise.graphenej.* import cy.agorise.graphenej.*
import cy.agorise.graphenej.api.ConnectionStatusUpdate import cy.agorise.graphenej.api.ConnectionStatusUpdate
import cy.agorise.graphenej.api.android.NetworkService
import cy.agorise.graphenej.api.android.RxBus
import cy.agorise.graphenej.api.calls.BroadcastTransaction import cy.agorise.graphenej.api.calls.BroadcastTransaction
import cy.agorise.graphenej.api.calls.GetAccountByName import cy.agorise.graphenej.api.calls.GetAccountByName
import cy.agorise.graphenej.api.calls.GetDynamicGlobalProperties import cy.agorise.graphenej.api.calls.GetDynamicGlobalProperties
@ -43,7 +35,6 @@ import cy.agorise.graphenej.models.DynamicGlobalProperties
import cy.agorise.graphenej.models.JsonRpcResponse import cy.agorise.graphenej.models.JsonRpcResponse
import cy.agorise.graphenej.operations.TransferOperationBuilder import cy.agorise.graphenej.operations.TransferOperationBuilder
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.fragment_send_transaction.* import kotlinx.android.synthetic.main.fragment_send_transaction.*
import me.dm7.barcodescanner.zxing.ZXingScannerView import me.dm7.barcodescanner.zxing.ZXingScannerView
@ -57,7 +48,7 @@ import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.crypto.AEADBadTagException import javax.crypto.AEADBadTagException
class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler, ServiceConnection { class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHandler {
private val TAG = this.javaClass.simpleName private val TAG = this.javaClass.simpleName
// Camera Permission // Camera Permission
@ -86,14 +77,6 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler, Serv
/** User account to which send the funds */ /** User account to which send the funds */
private var mSelectedUserAccount: UserAccount? = null private var mSelectedUserAccount: UserAccount? = null
private var mDisposables = CompositeDisposable()
/* Network service connection */
private var mNetworkService: NetworkService? = null
/** Flag used to keep track of the NetworkService binding state */
private var mShouldUnbindNetwork: Boolean = false
// Map used to keep track of request and response id pairs // Map used to keep track of request and response id pairs
private val responseMap = HashMap<Long, Int>() private val responseMap = HashMap<Long, Int>()
@ -213,36 +196,28 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler, Serv
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { validateAmount(it!!) } .subscribe { validateAmount(it!!) }
) )
// Connect to the RxBus, which receives events from the NetworkService
mDisposables.add(
RxBus.getBusInstance()
.asFlowable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { handleIncomingMessage(it) }
)
} }
private fun handleIncomingMessage(message: Any?) { override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) {
if (message is JsonRpcResponse<*>) { if (responseMap.containsKey(response.id)) {
if (responseMap.containsKey(message.id)) { val responseType = responseMap[response.id]
val responseType = responseMap[message.id]
when (responseType) { when (responseType) {
RESPONSE_GET_ACCOUNT_BY_NAME -> handleAccountName(message.result) RESPONSE_GET_ACCOUNT_BY_NAME -> handleAccountName(response.result)
RESPONSE_GET_DYNAMIC_GLOBAL_PARAMETERS -> handleDynamicGlobalProperties(message.result) RESPONSE_GET_DYNAMIC_GLOBAL_PARAMETERS -> handleDynamicGlobalProperties(response.result)
RESPONSE_GET_REQUIRED_FEES -> handleRequiredFees(message.result) RESPONSE_GET_REQUIRED_FEES -> handleRequiredFees(response.result)
RESPONSE_BROADCAST_TRANSACTION -> handleBroadcastTransaction(message) RESPONSE_BROADCAST_TRANSACTION -> handleBroadcastTransaction(response)
} }
responseMap.remove(message.id) responseMap.remove(response.id)
} }
} else if (message is ConnectionStatusUpdate) { }
if (message.updateCode == ConnectionStatusUpdate.DISCONNECTED) {
override fun handleConnectionStatusUpdate(connectionStatusUpdate: ConnectionStatusUpdate) {
if (connectionStatusUpdate.updateCode == ConnectionStatusUpdate.DISCONNECTED) {
// If we got a disconnection notification, we should clear our response map, since // If we got a disconnection notification, we should clear our response map, since
// all its stored request ids will now be reset // all its stored request ids will now be reset
responseMap.clear() responseMap.clear()
} }
} }
}
private fun handleAccountName(result: Any?) { private fun handleAccountName(result: Any?) {
if (result is AccountProperties) { if (result is AccountProperties) {
@ -481,39 +456,12 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler, Serv
super.onResume() super.onResume()
if (isCameraPreviewVisible) if (isCameraPreviewVisible)
startCameraPreview() startCameraPreview()
val intent = Intent(context, NetworkService::class.java)
if (context?.bindService(intent, this, Context.BIND_AUTO_CREATE) == true) {
mShouldUnbindNetwork = true
} else {
Log.e(TAG, "Binding to the network service failed.")
}
} }
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
// Unbinding from network service
if (mShouldUnbindNetwork) {
context?.unbindService(this)
mShouldUnbindNetwork = false
}
if (!isCameraPreviewVisible) if (!isCameraPreviewVisible)
stopCameraPreview() stopCameraPreview()
} }
override fun onDestroy() {
super.onDestroy()
if (!mDisposables.isDisposed) mDisposables.dispose()
}
override fun onServiceDisconnected(name: ComponentName?) { }
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
val binder = service as NetworkService.LocalBinder
mNetworkService = binder.service
}
} }