- 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:
parent
5388e90331
commit
4739e41fce
3 changed files with 119 additions and 2 deletions
|
@ -47,6 +47,7 @@ dependencies {
|
||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
implementation "androidx.room:room-rxjava2:$room_version" // RxJava support for Room
|
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 'org.bitcoinj:bitcoinj-core:0.14.3'
|
||||||
implementation 'com.moldedbits.r2d2:r2d2:1.0.1'
|
implementation 'com.moldedbits.r2d2:r2d2:1.0.1'
|
||||||
|
|
|
@ -6,7 +6,6 @@ import android.preference.PreferenceManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.collection.LongSparseArray
|
import androidx.collection.LongSparseArray
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
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.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -15,24 +21,39 @@ import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import com.google.zxing.BarcodeFormat
|
import com.google.zxing.BarcodeFormat
|
||||||
import com.google.zxing.Result
|
import com.google.zxing.Result
|
||||||
|
import com.jakewharton.rxbinding2.widget.RxTextView
|
||||||
import cy.agorise.bitsybitshareswallet.R
|
import cy.agorise.bitsybitshareswallet.R
|
||||||
import cy.agorise.bitsybitshareswallet.adapters.AssetsAdapter
|
import cy.agorise.bitsybitshareswallet.adapters.AssetsAdapter
|
||||||
import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail
|
import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail
|
||||||
|
import cy.agorise.bitsybitshareswallet.utils.Constants
|
||||||
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
|
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
|
||||||
import cy.agorise.graphenej.Invoice
|
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 kotlinx.android.synthetic.main.fragment_send_transaction.*
|
||||||
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import java.text.DecimalFormatSymbols
|
import java.text.DecimalFormatSymbols
|
||||||
import java.util.Locale
|
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
|
private val TAG = this.javaClass.simpleName
|
||||||
|
|
||||||
// Camera Permission
|
// Camera Permission
|
||||||
private val REQUEST_CAMERA_PERMISSION = 1
|
private val REQUEST_CAMERA_PERMISSION = 1
|
||||||
|
|
||||||
|
private val RESPONSE_GET_ACCOUNT_BY_NAME = 1
|
||||||
|
|
||||||
private var isCameraPreviewVisible = false
|
private var isCameraPreviewVisible = false
|
||||||
|
|
||||||
private var mBalancesDetails: List<BalanceDetail>? = null
|
private var mBalancesDetails: List<BalanceDetail>? = null
|
||||||
|
@ -43,6 +64,22 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
|
||||||
|
|
||||||
private var selectedAssetSymbol = ""
|
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? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_send_transaction, container, false)
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val userId = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "")
|
||||||
|
|
||||||
|
if (userId != "")
|
||||||
|
mUserAccount = UserAccount(userId)
|
||||||
|
|
||||||
verifyCameraPermission()
|
verifyCameraPermission()
|
||||||
|
|
||||||
fabOpenCamera.setOnClickListener { if (isCameraPreviewVisible) stopCameraPreview() else verifyCameraPermission() }
|
fabOpenCamera.setOnClickListener { if (isCameraPreviewVisible) stopCameraPreview() else verifyCameraPermission() }
|
||||||
|
@ -81,6 +124,52 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fabSendTransaction.setOnClickListener { validateFields() }
|
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() {
|
private fun verifyCameraPermission() {
|
||||||
|
@ -162,13 +251,27 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateFields() {
|
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() {
|
override fun onResume() {
|
||||||
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)) {
|
||||||
|
mShouldUnbindNetwork = true
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Binding to the network service failed.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
@ -176,4 +279,18 @@ class SendTransactionFragment : Fragment(), ZXingScannerView.ResultHandler {
|
||||||
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue