From 9a8af1b9188295d69c8fc355c94794f9ce0ca277 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Wed, 16 Jan 2019 11:34:01 -0600 Subject: [PATCH] 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. --- .../database/daos/AssetDao.kt | 4 +- .../fragments/ReceiveTransactionFragment.kt | 143 ++++++------------ .../repositories/AssetRepository.kt | 4 +- .../viewmodels/AssetViewModel.kt | 4 +- 4 files changed, 53 insertions(+), 102 deletions(-) diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/AssetDao.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/AssetDao.kt index b966ae2..8de0030 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/AssetDao.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/AssetDao.kt @@ -15,6 +15,6 @@ interface AssetDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertAll(assets: List) - @Query("SELECT * FROM assets") - fun getAll(): LiveData> + @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 getAllNonZero(): LiveData> } diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ReceiveTransactionFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ReceiveTransactionFragment.kt index f2d6190..19923dc 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ReceiveTransactionFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/ReceiveTransactionFragment.kt @@ -1,15 +1,11 @@ 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.graphics.Bitmap import android.graphics.Color import android.os.Bundle -import android.os.IBinder import android.preference.PreferenceManager import android.util.Log import android.view.* @@ -17,7 +13,6 @@ import android.widget.AdapterView import android.widget.Toast import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat -import androidx.fragment.app.Fragment import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProviders 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.graphenej.* 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.models.JsonRpcResponse import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable import kotlinx.android.synthetic.main.fragment_receive_transaction.* import java.lang.Exception import java.math.RoundingMode @@ -51,16 +43,19 @@ import java.util.* import java.util.concurrent.TimeUnit import kotlin.collections.ArrayList -class ReceiveTransactionFragment : Fragment(), ServiceConnection { - private val TAG = this.javaClass.simpleName +class ReceiveTransactionFragment : ConnectedFragment() { - private val RESPONSE_LIST_ASSETS = 1 - private val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100 + companion object { + private const val TAG = "ReceiveTransactionFrag" - /** Number of assets to request from the NetworkService to show as suggestions in the AutoCompleteTextView */ - private val AUTO_SUGGEST_ASSET_LIMIT = 5 + private const val RESPONSE_LIST_ASSETS = 1 + 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 mAssetViewModel: AssetViewModel @@ -68,8 +63,6 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection { /** Current user account */ private var mUserAccount: UserAccount? = null - private var mDisposables = CompositeDisposable() - private var mAsset: Asset? = 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 private val responseMap = HashMap() - /* 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? { setHasOptionsMenu(true) @@ -127,7 +114,7 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection { // Configure Assets spinner to show Assets already saved into the db mAssetViewModel = ViewModelProviders.of(this).get(AssetViewModel::class.java) - mAssetViewModel.getAll().observe(this, + mAssetViewModel.getAllNonZero().observe(this, Observer> { assets -> mAssets.clear() mAssets.addAll(assets) @@ -211,50 +198,49 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection { selectedInAutoCompleteTextView = true 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?) { - if (message is JsonRpcResponse<*>) { - if (responseMap.containsKey(message.id)) { - val responseType = responseMap[message.id] - when (responseType) { - RESPONSE_LIST_ASSETS -> handleListAssets(message.result as List) - } - 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() + override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) { + if (responseMap.containsKey(response.id)) { + val responseType = responseMap[response.id] + when (responseType) { + RESPONSE_LIST_ASSETS -> handleListAssets(response.result) } + responseMap.remove(response.id) } } - private fun handleListAssets(assetList: List) { - Log.d(TAG, "handleListAssets") - val assets = ArrayList() - 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) + override fun handleConnectionStatusUpdate(connectionStatusUpdate: ConnectionStatusUpdate) { + if (connectionStatusUpdate.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() + } + } + + /** + * 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. + */ + private fun handleListAssets(result: Any?) { + if (result is List<*> && result.isNotEmpty() && result[0] is Asset) { + val assetList = result as List + Log.d(TAG, "handleListAssets") + val assets = ArrayList() + 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() { @@ -422,39 +408,4 @@ class ReceiveTransactionFragment : Fragment(), ServiceConnection { shareIntent.type = "*/*" 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 - } } \ No newline at end of file diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt index 60aa72d..8ddd294 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/AssetRepository.kt @@ -16,8 +16,8 @@ class AssetRepository internal constructor(context: Context) { mAssetDao = db!!.assetDao() } - fun getAll(): LiveData> { - return mAssetDao.getAll() + fun getAllNonZero(): LiveData> { + return mAssetDao.getAllNonZero() } fun insertAll(assets: List) { diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/AssetViewModel.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/AssetViewModel.kt index 26fb10f..43c201c 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/AssetViewModel.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/AssetViewModel.kt @@ -9,7 +9,7 @@ import cy.agorise.bitsybitshareswallet.repositories.AssetRepository class AssetViewModel(application: Application) : AndroidViewModel(application) { private var mRepository = AssetRepository(application) - internal fun getAll(): LiveData> { - return mRepository.getAll() + internal fun getAllNonZero(): LiveData> { + return mRepository.getAllNonZero() } } \ No newline at end of file