Make ReceiveTransactionFragment extend from ConnectedFragment to reduce boilerplate and repeated code. Change the method used to obtain the Assets list from the db in ReceiveTransactionFragment, it now retrieved only those Assets for which the user has a Balance > 0. Improve ReceiveTransactionFragment's function that obtains the suggestions for the AutoCompleteTextView when the user wants to receive a different Asset, to avoid crashes if the information received does not have the expected format.

This commit is contained in:
Severiano Jaramillo 2019-01-16 11:34:01 -06:00
parent ec57bea829
commit 9a8af1b918
4 changed files with 53 additions and 102 deletions

View file

@ -15,6 +15,6 @@ interface AssetDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(assets: List<Asset>) fun insertAll(assets: List<Asset>)
@Query("SELECT * FROM assets") @Query("SELECT id, symbol, precision, description, bit_asset_id FROM assets INNER JOIN balances WHERE assets.id = balances.asset_id AND balances.asset_amount > 0")
fun getAll(): LiveData<List<Asset>> fun getAllNonZero(): LiveData<List<Asset>>
} }

View file

@ -1,15 +1,11 @@
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.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
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.*
@ -17,7 +13,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.google.common.primitives.UnsignedLong import com.google.common.primitives.UnsignedLong
@ -36,12 +31,9 @@ import cy.agorise.bitsybitshareswallet.viewmodels.AssetViewModel
import cy.agorise.bitsybitshareswallet.viewmodels.UserAccountViewModel import cy.agorise.bitsybitshareswallet.viewmodels.UserAccountViewModel
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.ListAssets import cy.agorise.graphenej.api.calls.ListAssets
import cy.agorise.graphenej.models.JsonRpcResponse import cy.agorise.graphenej.models.JsonRpcResponse
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_receive_transaction.* import kotlinx.android.synthetic.main.fragment_receive_transaction.*
import java.lang.Exception import java.lang.Exception
import java.math.RoundingMode import java.math.RoundingMode
@ -51,16 +43,19 @@ import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
class ReceiveTransactionFragment : Fragment(), ServiceConnection { class ReceiveTransactionFragment : ConnectedFragment() {
private val TAG = this.javaClass.simpleName
private val RESPONSE_LIST_ASSETS = 1 companion object {
private val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100 private const val TAG = "ReceiveTransactionFrag"
/** Number of assets to request from the NetworkService to show as suggestions in the AutoCompleteTextView */ private const val RESPONSE_LIST_ASSETS = 1
private val AUTO_SUGGEST_ASSET_LIMIT = 5 private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100
private val OTHER_ASSET = "other_asset" /** Number of assets to request from the NetworkService to show as suggestions in the AutoCompleteTextView */
private const val AUTO_SUGGEST_ASSET_LIMIT = 5
private const val OTHER_ASSET = "other_asset"
}
private lateinit var mUserAccountViewModel: UserAccountViewModel private lateinit var mUserAccountViewModel: UserAccountViewModel
private lateinit var mAssetViewModel: AssetViewModel private lateinit var mAssetViewModel: AssetViewModel
@ -68,8 +63,6 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection {
/** Current user account */ /** Current user account */
private var mUserAccount: UserAccount? = null private var mUserAccount: UserAccount? = null
private var mDisposables = CompositeDisposable()
private var mAsset: Asset? = null private var mAsset: Asset? = null
private var mAssetsAdapter: AssetsAdapter? = null private var mAssetsAdapter: AssetsAdapter? = null
@ -86,12 +79,6 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection {
// 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>()
/* Network service connection */
private var mNetworkService: NetworkService? = null
/** Flag used to keep track of the NetworkService binding state */
private var mShouldUnbindNetwork: Boolean = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
setHasOptionsMenu(true) setHasOptionsMenu(true)
@ -127,7 +114,7 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection {
// Configure Assets spinner to show Assets already saved into the db // Configure Assets spinner to show Assets already saved into the db
mAssetViewModel = ViewModelProviders.of(this).get(AssetViewModel::class.java) mAssetViewModel = ViewModelProviders.of(this).get(AssetViewModel::class.java)
mAssetViewModel.getAll().observe(this, mAssetViewModel.getAllNonZero().observe(this,
Observer<List<cy.agorise.bitsybitshareswallet.database.entities.Asset>> { assets -> Observer<List<cy.agorise.bitsybitshareswallet.database.entities.Asset>> { assets ->
mAssets.clear() mAssets.clear()
mAssets.addAll(assets) mAssets.addAll(assets)
@ -211,50 +198,49 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection {
selectedInAutoCompleteTextView = true selectedInAutoCompleteTextView = true
updateQR() updateQR()
} }
// 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_LIST_ASSETS -> handleListAssets(response.result)
RESPONSE_LIST_ASSETS -> handleListAssets(message.result as List<Asset>)
}
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()
} }
responseMap.remove(response.id)
} }
} }
private fun handleListAssets(assetList: List<Asset>) { override fun handleConnectionStatusUpdate(connectionStatusUpdate: ConnectionStatusUpdate) {
Log.d(TAG, "handleListAssets") if (connectionStatusUpdate.updateCode == ConnectionStatusUpdate.DISCONNECTED) {
val assets = ArrayList<cy.agorise.bitsybitshareswallet.database.entities.Asset>() // If we got a disconnection notification, we should clear our response map, since
for (_asset in assetList) { // all its stored request ids will now be reset
val asset = cy.agorise.bitsybitshareswallet.database.entities.Asset( responseMap.clear()
_asset.objectId, }
_asset.symbol, }
_asset.precision,
_asset.description ?: "", /**
_asset.bitassetId ?: "" * Handles the list of assets returned from the node that correspond to what the user has typed in the Asset
) * AutoCompleteTextView and adds them to its adapter to show as suggestions.
*/
assets.add(asset) private fun handleListAssets(result: Any?) {
if (result is List<*> && result.isNotEmpty() && result[0] is Asset) {
val assetList = result as List<Asset>
Log.d(TAG, "handleListAssets")
val assets = ArrayList<cy.agorise.bitsybitshareswallet.database.entities.Asset>()
for (_asset in assetList) {
val asset = cy.agorise.bitsybitshareswallet.database.entities.Asset(
_asset.objectId,
_asset.symbol,
_asset.precision,
_asset.description ?: "",
_asset.bitassetId ?: ""
)
assets.add(asset)
}
mAutoSuggestAssetAdapter.setData(assets)
mAutoSuggestAssetAdapter.notifyDataSetChanged()
} }
mAutoSuggestAssetAdapter.setData(assets)
mAutoSuggestAssetAdapter.notifyDataSetChanged()
} }
private fun updateQR() { private fun updateQR() {
@ -422,39 +408,4 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection {
shareIntent.type = "*/*" shareIntent.type = "*/*"
startActivity(Intent.createChooser(shareIntent, getString(R.string.text__share_with))) startActivity(Intent.createChooser(shareIntent, getString(R.string.text__share_with)))
} }
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
}
} }

View file

@ -16,8 +16,8 @@ class AssetRepository internal constructor(context: Context) {
mAssetDao = db!!.assetDao() mAssetDao = db!!.assetDao()
} }
fun getAll(): LiveData<List<Asset>> { fun getAllNonZero(): LiveData<List<Asset>> {
return mAssetDao.getAll() return mAssetDao.getAllNonZero()
} }
fun insertAll(assets: List<Asset>) { fun insertAll(assets: List<Asset>) {

View file

@ -9,7 +9,7 @@ import cy.agorise.bitsybitshareswallet.repositories.AssetRepository
class AssetViewModel(application: Application) : AndroidViewModel(application) { class AssetViewModel(application: Application) : AndroidViewModel(application) {
private var mRepository = AssetRepository(application) private var mRepository = AssetRepository(application)
internal fun getAll(): LiveData<List<Asset>> { internal fun getAllNonZero(): LiveData<List<Asset>> {
return mRepository.getAll() return mRepository.getAllNonZero()
} }
} }