- Added the RxBindings library to be able to use RxJava on Android Widgets.

- Connected the SendTransactionFragment to Graphenej's NetworkService so that it can directly send requests to the nodes.
- Added the RxBus to SendTransactionsFragment so that it can listen to responses from the NetworkService and take the useful ones.
- Added account validation to SendTransactionFragment, if the account typed exists then the Send button is enabled, if not the button is disabled an a error is shown below the typed account.
This commit is contained in:
Severiano Jaramillo 2018-12-05 18:38:34 -06:00
parent 5388e90331
commit 4739e41fce
3 changed files with 119 additions and 2 deletions

View file

@ -47,6 +47,7 @@ dependencies {
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-rxjava2:$room_version" // RxJava support for Room
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
implementation 'org.bitcoinj:bitcoinj-core:0.14.3'
implementation 'com.moldedbits.r2d2:r2d2:1.0.1'

View file

@ -6,7 +6,6 @@ import android.preference.PreferenceManager
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.collection.LongSparseArray
import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView

View file

@ -1,8 +1,14 @@
package cy.agorise.bitsybitshareswallet.fragments
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.os.Bundle
import android.os.IBinder
import android.preference.PreferenceManager
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@ -15,24 +21,39 @@ import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.google.zxing.BarcodeFormat
import com.google.zxing.Result
import com.jakewharton.rxbinding2.widget.RxTextView
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.adapters.AssetsAdapter
import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail
import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
import cy.agorise.graphenej.Invoice
import cy.agorise.graphenej.UserAccount
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.GetAccountByName
import cy.agorise.graphenej.models.AccountProperties
import cy.agorise.graphenej.models.JsonRpcResponse
import cy.agorise.graphenej.operations.TransferOperationBuilder
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_send_transaction.*
import me.dm7.barcodescanner.zxing.ZXingScannerView
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
import java.util.concurrent.TimeUnit
class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler, ServiceConnection {
private val TAG = this.javaClass.simpleName
// Camera Permission
private val REQUEST_CAMERA_PERMISSION = 1
private val RESPONSE_GET_ACCOUNT_BY_NAME = 1
private var isCameraPreviewVisible = false
private var mBalancesDetails: List<BalanceDetail>? = null
@ -43,6 +64,22 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
private var selectedAssetSymbol = ""
/** Current user account */
private var mUserAccount: UserAccount? = null
/** User account to which send the funds */
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
private val responseMap = HashMap<Long, Int>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_send_transaction, container, false)
@ -51,6 +88,12 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val userId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "")
if (userId != "")
mUserAccount = UserAccount(userId)
verifyCameraPermission()
fabOpenCamera.setOnClickListener { if (isCameraPreviewVisible) stopCameraPreview() else verifyCameraPermission() }
@ -81,6 +124,52 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
}
fabSendTransaction.setOnClickListener { validateFields() }
fabSendTransaction.hide()
// Use RxJava Debounce to avoid making calls to the NetworkService on every text change event
mDisposables.add(RxTextView.textChanges(tietTo)
.map { it.toString().trim() }
.filter { it.length > 1 }
.debounce(500, TimeUnit.MILLISECONDS)
.subscribe {
val id = mNetworkService!!.sendMessage(GetAccountByName(it!!), GetAccountByName.REQUIRED_API)
responseMap[id] = RESPONSE_GET_ACCOUNT_BY_NAME
}
)
mDisposables.add(RxBus.getBusInstance()
.asFlowable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { message ->
if (message is JsonRpcResponse<*>) {
if (responseMap.containsKey(message.id)) {
val responseType = responseMap[message.id]
when (responseType) {
RESPONSE_GET_ACCOUNT_BY_NAME -> handleAccountName(message.result)
}
responseMap.remove(message.id)
}
} else if (message is ConnectionStatusUpdate) {
if (message.updateCode == ConnectionStatusUpdate.DISCONNECTED) {
// If we got a disconnection notification, we should clear our response map, since
// all its stored request ids will now be reset
responseMap.clear()
}
}
}
)
}
private fun handleAccountName(result: Any?) {
if (result is AccountProperties) {
mSelectedUserAccount = UserAccount(result.id, result.name)
tilTo.isErrorEnabled = false
fabSendTransaction.show()
} else {
mSelectedUserAccount = null
tilTo.error = "Invalid account"
fabSendTransaction.hide()
}
}
private fun verifyCameraPermission() {
@ -162,13 +251,27 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
}
private fun validateFields() {
tilAmount.isErrorEnabled = false
// val selectedAsset = mAssetsAdapter!!.getItem(spAsset.selectedItemPosition)
// val selectedAmount = tietAmount.getTex
// Create TransferOperation
val builder = TransferOperationBuilder()
builder.setSource(mUserAccount)
}
override fun onResume() {
super.onResume()
if (isCameraPreviewVisible)
startCameraPreview()
val intent = Intent(context, NetworkService::class.java)
if (context!!.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
mShouldUnbindNetwork = true
} else {
Log.e(TAG, "Binding to the network service failed.")
}
}
override fun onPause() {
@ -176,4 +279,18 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
if (!isCameraPreviewVisible)
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
}
}