Update Navigation and Lifecycle libraries.

- Updated the Navigation architecture component library to the latest stable version, with no big changes required.
- Updated the Lifecycle architecture component library to the latest stable version, along with a bunch of changes related to the deprecation of some methods and the addition of others.
This commit is contained in:
Severiano Jaramillo 2021-03-22 22:31:40 -07:00
parent fd68b8bb96
commit be5c9bcea7
15 changed files with 312 additions and 308 deletions

View file

@ -63,7 +63,7 @@ android {
} }
dependencies { dependencies {
def lifecycle_version = "2.2.0" def lifecycle_version = "2.3.0"
def arch_version = "2.1.0" def arch_version = "2.1.0"
def room_version = "2.2.6" def room_version = "2.2.6"
def rx_bindings_version = '3.0.0' def rx_bindings_version = '3.0.0'
@ -83,8 +83,8 @@ dependencies {
implementation 'com.google.android.gms:play-services-maps:17.0.0' implementation 'com.google.android.gms:play-services-maps:17.0.0'
implementation 'com.google.maps.android:android-maps-utils:0.5' implementation 'com.google.maps.android:android-maps-utils:0.5'
// AAC Lifecycle // AAC Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" // viewModelScope implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// AAC Room // AAC Room
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"

View file

@ -7,10 +7,9 @@ import android.os.Handler
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import cy.agorise.bitsybitshareswallet.database.entities.Balance import cy.agorise.bitsybitshareswallet.database.entities.Balance
import cy.agorise.bitsybitshareswallet.database.entities.Transfer import cy.agorise.bitsybitshareswallet.database.entities.Transfer
@ -69,10 +68,11 @@ abstract class ConnectedActivity : AppCompatActivity() {
private const val RESPONSE_GET_MARKET_HISTORY = 6 private const val RESPONSE_GET_MARKET_HISTORY = 6
} }
private lateinit var mUserAccountViewModel: UserAccountViewModel // TODO consolidate ViewModels
private lateinit var mBalanceViewModel: BalanceViewModel private val userAccountViewModel: UserAccountViewModel by viewModels()
private lateinit var mTransferViewModel: TransferViewModel private val balanceViewModel: BalanceViewModel by viewModels()
private lateinit var mConnectedActivityViewModel: ConnectedActivityViewModel private val transferViewModel: TransferViewModel by viewModels()
private val connectedActivityViewModel: ConnectedActivityViewModel by viewModels()
private lateinit var mAssetRepository: AssetRepository private lateinit var mAssetRepository: AssetRepository
@ -114,42 +114,38 @@ abstract class ConnectedActivity : AppCompatActivity() {
mAssetRepository = AssetRepository(this) mAssetRepository = AssetRepository(this)
// Configure ConnectedActivityViewModel to obtain missing equivalent values // Configure ConnectedActivityViewModel to obtain missing equivalent values
mConnectedActivityViewModel = ViewModelProviders.of(this).get(ConnectedActivityViewModel::class.java)
val currencyCode = Helper.getCoingeckoSupportedCurrency(Locale.getDefault()) val currencyCode = Helper.getCoingeckoSupportedCurrency(Locale.getDefault())
Log.d(TAG, "Using currency: ${currencyCode.toUpperCase(Locale.ROOT)}") Log.d(TAG, "Using currency: ${currencyCode.toUpperCase(Locale.ROOT)}")
mConnectedActivityViewModel.observeMissingEquivalentValuesIn(currencyCode) connectedActivityViewModel.observeMissingEquivalentValuesIn(currencyCode)
// Configure UserAccountViewModel to obtain the missing account ids // Configure UserAccountViewModel to obtain the missing account ids
mUserAccountViewModel = ViewModelProviders.of(this).get(UserAccountViewModel::class.java) userAccountViewModel.getMissingUserAccountIds().observe(this, { userAccountIds ->
mUserAccountViewModel.getMissingUserAccountIds().observe(this, Observer<List<String>>{ userAccountIds ->
if (userAccountIds.isNotEmpty()) { if (userAccountIds.isNotEmpty()) {
missingUserAccounts.clear() missingUserAccounts.clear()
for (userAccountId in userAccountIds) for (userAccountId in userAccountIds)
missingUserAccounts.add(UserAccount(userAccountId)) missingUserAccounts.add(UserAccount(userAccountId))
mHandler.postDelayed(mRequestMissingUserAccountsTask, Constants.NETWORK_SERVICE_RETRY_PERIOD) mHandler.postDelayed(
mRequestMissingUserAccountsTask,
Constants.NETWORK_SERVICE_RETRY_PERIOD
)
} }
}) })
// Configure UserAccountViewModel to obtain the missing account ids // Configure UserAccountViewModel to obtain the missing account ids
mBalanceViewModel = ViewModelProviders.of(this).get(BalanceViewModel::class.java) balanceViewModel.getMissingAssetIds().observe(this, { assetIds ->
mBalanceViewModel.getMissingAssetIds().observe(this, Observer<List<String>>{ assetIds ->
if (assetIds.isNotEmpty()) { if (assetIds.isNotEmpty()) {
missingAssets.clear() missingAssets.clear()
for (assetId in assetIds) for (assetId in assetIds)
missingAssets.add(Asset(assetId)) missingAssets.add(Asset(assetId))
mHandler.postDelayed(mRequestMissingAssetsTask, Constants.NETWORK_SERVICE_RETRY_PERIOD) mHandler
.postDelayed(mRequestMissingAssetsTask, Constants.NETWORK_SERVICE_RETRY_PERIOD)
} }
}) })
//Configure TransferViewModel to obtain the Transfer's block numbers with missing time information, one by one //Configure TransferViewModel to obtain the Transfer's block numbers with missing time information, one by one
mTransferViewModel = ViewModelProviders.of(this).get(TransferViewModel::class.java) transferViewModel.getTransferBlockNumberWithMissingTime().observe(this, { blockNumber ->
mTransferViewModel.getTransferBlockNumberWithMissingTime().observe(this, Observer<Long>{ blockNumber ->
if (blockNumber != null && blockNumber != blockNumberWithMissingTime) { if (blockNumber != null && blockNumber != blockNumberWithMissingTime) {
blockNumberWithMissingTime = blockNumber blockNumberWithMissingTime = blockNumber
mHandler.post(mRequestBlockMissingTimeTask) mHandler.post(mRequestBlockMissingTimeTask)
@ -167,13 +163,14 @@ abstract class ConnectedActivity : AppCompatActivity() {
mCompositeDisposable.add(disposable) mCompositeDisposable.add(disposable)
val info = this.packageManager.getPackageInfo(this.packageName, PackageManager.GET_ACTIVITIES) val info =
this.packageManager.getPackageInfo(this.packageName, PackageManager.GET_ACTIVITIES)
val versionCode = PackageInfoCompat.getLongVersionCode(info) val versionCode = PackageInfoCompat.getLongVersionCode(info)
val hasPurgedEquivalentValues = PreferenceManager.getDefaultSharedPreferences(this) val hasPurgedEquivalentValues = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, false) .getBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, false)
if(versionCode > 11 && !hasPurgedEquivalentValues) { if (versionCode > 11 && !hasPurgedEquivalentValues) {
thread { thread {
mConnectedActivityViewModel.purgeEquivalentValues() connectedActivityViewModel.purgeEquivalentValues()
PreferenceManager.getDefaultSharedPreferences(this) PreferenceManager.getDefaultSharedPreferences(this)
.edit() .edit()
.putBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, true) .putBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, true)
@ -201,7 +198,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
* Error consumer used to handle potential errors caused by the NetworkService while processing * Error consumer used to handle potential errors caused by the NetworkService while processing
* incoming data. * incoming data.
*/ */
private fun handleError(throwable: Throwable){ private fun handleError(throwable: Throwable) {
Log.e(TAG, "Error while processing received message. Msg: " + throwable.message) Log.e(TAG, "Error while processing received message. Msg: " + throwable.message)
val stack = throwable.stackTrace val stack = throwable.stackTrace
for (e in stack) { for (e in stack) {
@ -259,11 +256,11 @@ abstract class ConnectedActivity : AppCompatActivity() {
responseMap.clear() responseMap.clear()
} else if (message.updateCode == ConnectionStatusUpdate.API_UPDATE) { } else if (message.updateCode == ConnectionStatusUpdate.API_UPDATE) {
// If we got an API update // If we got an API update
if(message.api == ApiAccess.API_HISTORY) { if (message.api == ApiAccess.API_HISTORY) {
// Starts the procedure that will obtain the missing equivalent values // Starts the procedure that will obtain the missing equivalent values
mTransferViewModel transferViewModel
.getTransfersWithMissingBtsValue().observe(this, Observer<Transfer> { .getTransfersWithMissingBtsValue().observe(this, {
if(it != null) handleTransfersWithMissingBtsValue(it) if (it != null) handleTransfersWithMissingBtsValue(it)
}) })
} }
} }
@ -274,13 +271,16 @@ abstract class ConnectedActivity : AppCompatActivity() {
* Method called whenever we get a list of transfers with their bts value missing. * Method called whenever we get a list of transfers with their bts value missing.
*/ */
private fun handleTransfersWithMissingBtsValue(transfer: Transfer) { private fun handleTransfersWithMissingBtsValue(transfer: Transfer) {
if(mNetworkService?.isConnected == true){ if (mNetworkService?.isConnected == true) {
val base = Asset(transfer.transferAssetId) val base = Asset(transfer.transferAssetId)
val quote = Asset("1.3.0") val quote = Asset("1.3.0")
val bucket: Long = TimeUnit.SECONDS.convert(1, TimeUnit.DAYS) val bucket: Long = TimeUnit.SECONDS.convert(1, TimeUnit.DAYS)
val end: Long = transfer.timestamp * 1000L val end: Long = transfer.timestamp * 1000L
val start: Long = (transfer.timestamp - bucket) * 1000L val start: Long = (transfer.timestamp - bucket) * 1000L
val id = mNetworkService!!.sendMessage(GetMarketHistory(base, quote, bucket, start, end), GetMarketHistory.REQUIRED_API) val id = mNetworkService!!.sendMessage(
GetMarketHistory(base, quote, bucket, start, end),
GetMarketHistory.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_MARKET_HISTORY responseMap[id] = RESPONSE_GET_MARKET_HISTORY
this.transfer = transfer this.transfer = transfer
} }
@ -292,11 +292,17 @@ abstract class ConnectedActivity : AppCompatActivity() {
*/ */
private fun handleAccountDetails(accountDetails: FullAccountDetails) { private fun handleAccountDetails(accountDetails: FullAccountDetails) {
val latestOpCount = accountDetails.statistics.total_ops val latestOpCount = accountDetails.statistics.total_ops
Log.d(TAG, "handleAccountDetails. prev count: $storedOpCount, current count: $latestOpCount") Log.d(
TAG,
"handleAccountDetails. prev count: $storedOpCount, current count: $latestOpCount"
)
if (latestOpCount == 0L) { if (latestOpCount == 0L) {
Log.d(TAG, "The node returned 0 total_ops for current account and may not have installed the history plugin. " + Log.d(
"\nAsk the NetworkService to remove the node from the list and connect to another one.") TAG,
"The node returned 0 total_ops for current account and may not have installed the history plugin. " +
"\nAsk the NetworkService to remove the node from the list and connect to another one."
)
mNetworkService?.reconnectNode() mNetworkService?.reconnectNode()
} else if (storedOpCount == -1L) { } else if (storedOpCount == -1L) {
// Initial case when the app starts // Initial case when the app starts
@ -317,7 +323,8 @@ abstract class ConnectedActivity : AppCompatActivity() {
* create a list of BiTSy's UserAccount objects and stores them into the database * create a list of BiTSy's UserAccount objects and stores them into the database
*/ */
private fun handleAccountProperties(accountPropertiesList: List<AccountProperties>) { private fun handleAccountProperties(accountPropertiesList: List<AccountProperties>) {
val userAccounts = ArrayList<cy.agorise.bitsybitshareswallet.database.entities.UserAccount>() val userAccounts =
ArrayList<cy.agorise.bitsybitshareswallet.database.entities.UserAccount>()
for (accountProperties in accountPropertiesList) { for (accountProperties in accountPropertiesList) {
val userAccount = cy.agorise.bitsybitshareswallet.database.entities.UserAccount( val userAccount = cy.agorise.bitsybitshareswallet.database.entities.UserAccount(
@ -329,7 +336,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
userAccounts.add(userAccount) userAccounts.add(userAccount)
} }
mUserAccountViewModel.insertAll(userAccounts) userAccountViewModel.insertAll(userAccounts)
missingUserAccounts.clear() missingUserAccounts.clear()
} }
@ -346,7 +353,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
balances.add(balance) balances.add(balance)
} }
mBalanceViewModel.insertAll(balances) balanceViewModel.insertAll(balances)
} }
/** /**
@ -382,35 +389,38 @@ abstract class ConnectedActivity : AppCompatActivity() {
try { try {
val date = dateFormat.parse(blockHeader.timestamp) val date = dateFormat.parse(blockHeader.timestamp)
mTransferViewModel.setBlockTime(blockNumber, date.time / 1000) transferViewModel.setBlockTime(blockNumber, date.time / 1000)
} catch (e: ParseException) { } catch (e: ParseException) {
Log.e(TAG, "ParseException. Msg: " + e.message) Log.e(TAG, "ParseException. Msg: " + e.message)
} }
} }
private fun handleMarketData(buckets: List<BucketObject>) { private fun handleMarketData(buckets: List<BucketObject>) {
if(buckets.isNotEmpty()){ if (buckets.isNotEmpty()) {
Log.d(TAG,"handleMarketData. Bucket is not empty") Log.d(TAG, "handleMarketData. Bucket is not empty")
val bucket = buckets[0] val bucket = buckets[0]
val pair = Pair(transfer, bucket) val pair = Pair(transfer, bucket)
val disposable = Observable.just(pair) val disposable = Observable.just(pair)
.subscribeOn(Schedulers.computation()) .subscribeOn(Schedulers.computation())
.map { mTransferViewModel.updateBtsValue(it.first!!, it.second) } .map { transferViewModel.updateBtsValue(it.first!!, it.second) }
.subscribe({},{ .subscribe({}, {
Log.e(TAG,"Error at updateBtsValue. Msg: ${it.message}") Log.e(TAG, "Error at updateBtsValue. Msg: ${it.message}")
for(line in it.stackTrace) Log.e(TAG, "${line.className}#${line.methodName}:${line.lineNumber}") for (line in it.stackTrace)
Log.e(TAG, "${line.className}#${line.methodName}:${line.lineNumber}")
}) })
mCompositeDisposable.add(disposable) mCompositeDisposable.add(disposable)
}else{ } else {
Log.i(TAG,"handleMarketData. Bucket IS empty") Log.i(TAG, "handleMarketData. Bucket IS empty")
AsyncTask.execute { mTransferViewModel.updateBtsValue(transfer!!, Transfer.ERROR) } AsyncTask.execute { transferViewModel.updateBtsValue(transfer!!, Transfer.ERROR) }
} }
} }
private fun updateBalances() { private fun updateBalances() {
if (mNetworkService?.isConnected == true) { if (mNetworkService?.isConnected == true) {
val id = mNetworkService!!.sendMessage(GetAccountBalances(mCurrentAccount, ArrayList()), val id = mNetworkService!!.sendMessage(
GetAccountBalances.REQUIRED_API) GetAccountBalances(mCurrentAccount, ArrayList()),
GetAccountBalances.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_ACCOUNT_BALANCES responseMap[id] = RESPONSE_GET_ACCOUNT_BALANCES
} }
@ -447,10 +457,13 @@ abstract class ConnectedActivity : AppCompatActivity() {
private val mRequestMissingUserAccountsTask = object : Runnable { private val mRequestMissingUserAccountsTask = object : Runnable {
override fun run() { override fun run() {
if (mNetworkService?.isConnected == true) { if (mNetworkService?.isConnected == true) {
val id = mNetworkService!!.sendMessage(GetAccounts(missingUserAccounts), GetAccounts.REQUIRED_API) val id = mNetworkService!!.sendMessage(
GetAccounts(missingUserAccounts),
GetAccounts.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_ACCOUNTS responseMap[id] = RESPONSE_GET_ACCOUNTS
} else if (missingUserAccounts.isNotEmpty()){ } else if (missingUserAccounts.isNotEmpty()) {
mHandler.postDelayed(this, Constants.NETWORK_SERVICE_RETRY_PERIOD) mHandler.postDelayed(this, Constants.NETWORK_SERVICE_RETRY_PERIOD)
} }
} }
@ -462,10 +475,11 @@ abstract class ConnectedActivity : AppCompatActivity() {
private val mRequestMissingAssetsTask = object : Runnable { private val mRequestMissingAssetsTask = object : Runnable {
override fun run() { override fun run() {
if (mNetworkService?.isConnected == true) { if (mNetworkService?.isConnected == true) {
val id = mNetworkService!!.sendMessage(GetAssets(missingAssets), GetAssets.REQUIRED_API) val id =
mNetworkService!!.sendMessage(GetAssets(missingAssets), GetAssets.REQUIRED_API)
responseMap[id] = RESPONSE_GET_ASSETS responseMap[id] = RESPONSE_GET_ASSETS
} else if (missingAssets.isNotEmpty()){ } else if (missingAssets.isNotEmpty()) {
mHandler.postDelayed(this, Constants.NETWORK_SERVICE_RETRY_PERIOD) mHandler.postDelayed(this, Constants.NETWORK_SERVICE_RETRY_PERIOD)
} }
} }
@ -480,13 +494,17 @@ abstract class ConnectedActivity : AppCompatActivity() {
if (mCurrentAccount != null) { if (mCurrentAccount != null) {
val userAccounts = ArrayList<String>() val userAccounts = ArrayList<String>()
userAccounts.add(mCurrentAccount!!.objectId) userAccounts.add(mCurrentAccount!!.objectId)
val id = mNetworkService!!.sendMessage(GetFullAccounts(userAccounts, false), val id = mNetworkService!!.sendMessage(
GetFullAccounts.REQUIRED_API) GetFullAccounts(userAccounts, false),
GetFullAccounts.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_FULL_ACCOUNTS responseMap[id] = RESPONSE_GET_FULL_ACCOUNTS
} }
} else { } else {
Log.w(TAG, "NetworkService is null or is not connected. mNetworkService: $mNetworkService") val msg = "NetworkService is null or is not connected. " +
"mNetworkService: $mNetworkService"
Log.w(TAG, msg)
} }
mHandler.postDelayed(this, Constants.MISSING_PAYMENT_CHECK_PERIOD) mHandler.postDelayed(this, Constants.MISSING_PAYMENT_CHECK_PERIOD)
@ -500,8 +518,10 @@ abstract class ConnectedActivity : AppCompatActivity() {
override fun run() { override fun run() {
if (mNetworkService?.isConnected == true) { if (mNetworkService?.isConnected == true) {
val id = mNetworkService!!.sendMessage(GetBlockHeader(blockNumberWithMissingTime), val id = mNetworkService!!.sendMessage(
GetBlockHeader.REQUIRED_API) GetBlockHeader(blockNumberWithMissingTime),
GetBlockHeader.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_BLOCK_HEADER responseMap[id] = RESPONSE_GET_BLOCK_HEADER
requestIdToBlockNumberMap[id] = blockNumberWithMissingTime requestIdToBlockNumberMap[id] = blockNumberWithMissingTime
@ -521,7 +541,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
mNetworkService?.nodeLatencyVerifier?.nodeList?.let { nodes -> mNetworkService?.nodeLatencyVerifier?.nodeList?.let { nodes ->
mConnectedActivityViewModel.updateNodeLatencies(nodes as List<FullNode>) connectedActivityViewModel.updateNodeLatencies(nodes as List<FullNode>)
} }
mHandler.removeCallbacks(mCheckMissingPaymentsTask) mHandler.removeCallbacks(mCheckMissingPaymentsTask)
@ -532,6 +552,6 @@ abstract class ConnectedActivity : AppCompatActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
if(!mCompositeDisposable.isDisposed) mCompositeDisposable.dispose() if (!mCompositeDisposable.isDisposed) mCompositeDisposable.dispose()
} }
} }

View file

@ -5,22 +5,20 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import cy.agorise.bitsybitshareswallet.adapters.BalancesAdapter import cy.agorise.bitsybitshareswallet.adapters.BalancesAdapter
import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail
import cy.agorise.bitsybitshareswallet.databinding.FragmentBalancesBinding import cy.agorise.bitsybitshareswallet.databinding.FragmentBalancesBinding
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
class BalancesFragment : Fragment() { class BalancesFragment : Fragment() {
private val viewModel: BalanceDetailViewModel by viewModels()
private var _binding: FragmentBalancesBinding? = null private var _binding: FragmentBalancesBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@ -40,18 +38,14 @@ class BalancesFragment : Fragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// Configure BalanceDetailViewModel to show the current balances // Configure BalanceDetailViewModel to show the current balances
mBalanceDetailViewModel = val balancesAdapter = BalancesAdapter(requireContext())
ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java)
val balancesAdapter = BalancesAdapter(context!!)
binding.rvBalances.adapter = balancesAdapter binding.rvBalances.adapter = balancesAdapter
binding.rvBalances.layoutManager = LinearLayoutManager(context!!) binding.rvBalances.layoutManager = LinearLayoutManager(requireContext())
binding.rvBalances.addItemDecoration( binding.rvBalances.addItemDecoration(
DividerItemDecoration(context!!, DividerItemDecoration.VERTICAL) DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)
) )
mBalanceDetailViewModel.getAll() viewModel.getAll().observe(viewLifecycleOwner, { balancesDetails ->
.observe(this, Observer<List<BalanceDetail>> { balancesDetails ->
balancesAdapter.replaceAll(balancesDetails) balancesAdapter.replaceAll(balancesDetails)
}) })
} }

View file

@ -3,6 +3,7 @@ package cy.agorise.bitsybitshareswallet.fragments
import android.preference.PreferenceManager import android.preference.PreferenceManager
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.activities.ConnectedActivity
import cy.agorise.bitsybitshareswallet.database.entities.Authority import cy.agorise.bitsybitshareswallet.database.entities.Authority
import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository
import cy.agorise.bitsybitshareswallet.repositories.UserAccountRepository import cy.agorise.bitsybitshareswallet.repositories.UserAccountRepository
@ -13,7 +14,6 @@ import cy.agorise.graphenej.BrainKey
import cy.agorise.graphenej.PublicKey import cy.agorise.graphenej.PublicKey
import cy.agorise.graphenej.models.AccountProperties import cy.agorise.graphenej.models.AccountProperties
import org.bitcoinj.core.ECKey import org.bitcoinj.core.ECKey
import cy.agorise.bitsybitshareswallet.activities.ConnectedActivity
abstract class BaseAccountFragment : ConnectedFragment() { abstract class BaseAccountFragment : ConnectedFragment() {
@ -36,7 +36,7 @@ abstract class BaseAccountFragment : ConnectedFragment() {
val hashedPIN = CryptoUtils.createSHA256Hash(salt + pin) val hashedPIN = CryptoUtils.createSHA256Hash(salt + pin)
// Stores the user selected PIN, hashed // Stores the user selected PIN, hashed
PreferenceManager.getDefaultSharedPreferences(context!!).edit() PreferenceManager.getDefaultSharedPreferences(requireContext()).edit()
.putString(Constants.KEY_HASHED_PIN_PATTERN, hashedPIN) .putString(Constants.KEY_HASHED_PIN_PATTERN, hashedPIN)
.putString(Constants.KEY_PIN_PATTERN_SALT, salt) .putString(Constants.KEY_PIN_PATTERN_SALT, salt)
.putInt(Constants.KEY_SECURITY_LOCK_SELECTED, 1).apply() // 1 -> PIN .putInt(Constants.KEY_SECURITY_LOCK_SELECTED, 1).apply() // 1 -> PIN
@ -44,15 +44,17 @@ abstract class BaseAccountFragment : ConnectedFragment() {
// Stores the accounts this key refers to // Stores the accounts this key refers to
val id = accountProperties.id val id = accountProperties.id
val name = accountProperties.name val name = accountProperties.name
val isLTM = accountProperties.membership_expiration_date == Constants.LIFETIME_EXPIRATION_DATE val isLTM =
accountProperties.membership_expiration_date == Constants.LIFETIME_EXPIRATION_DATE
val userAccount = cy.agorise.bitsybitshareswallet.database.entities.UserAccount(id, name, isLTM) val userAccount =
cy.agorise.bitsybitshareswallet.database.entities.UserAccount(id, name, isLTM)
val userAccountRepository = UserAccountRepository(context!!.applicationContext) val userAccountRepository = UserAccountRepository(requireContext().applicationContext)
userAccountRepository.insert(userAccount) userAccountRepository.insert(userAccount)
// Stores the id of the currently active user account // Stores the id of the currently active user account
PreferenceManager.getDefaultSharedPreferences(context!!).edit() PreferenceManager.getDefaultSharedPreferences(requireContext()).edit()
.putString(Constants.KEY_CURRENT_ACCOUNT_ID, accountProperties.id).apply() .putString(Constants.KEY_CURRENT_ACCOUNT_ID, accountProperties.id).apply()
// Trying to store all possible authorities (owner, active and memo) into the database // Trying to store all possible authorities (owner, active and memo) into the database
@ -65,13 +67,25 @@ abstract class BaseAccountFragment : ConnectedFragment() {
val publicKey = PublicKey(ECKey.fromPublicOnly(mBrainKey!!.privateKey.pubKey)) val publicKey = PublicKey(ECKey.fromPublicOnly(mBrainKey!!.privateKey.pubKey))
if (ownerAuthority.keyAuths.keys.contains(publicKey)) { if (ownerAuthority.keyAuths.keys.contains(publicKey)) {
addAuthorityToDatabase(accountProperties.id, AuthorityType.OWNER.ordinal, mBrainKey!!) addAuthorityToDatabase(
accountProperties.id,
AuthorityType.OWNER.ordinal,
mBrainKey!!
)
} }
if (activeAuthority.keyAuths.keys.contains(publicKey)) { if (activeAuthority.keyAuths.keys.contains(publicKey)) {
addAuthorityToDatabase(accountProperties.id, AuthorityType.ACTIVE.ordinal, mBrainKey!!) addAuthorityToDatabase(
accountProperties.id,
AuthorityType.ACTIVE.ordinal,
mBrainKey!!
)
} }
if (options.memoKey == publicKey) { if (options.memoKey == publicKey) {
addAuthorityToDatabase(accountProperties.id, AuthorityType.MEMO.ordinal, mBrainKey!!) addAuthorityToDatabase(
accountProperties.id,
AuthorityType.MEMO.ordinal,
mBrainKey!!
)
} }
} }
@ -91,13 +105,21 @@ abstract class BaseAccountFragment : ConnectedFragment() {
val wif = brainKey.walletImportFormat val wif = brainKey.walletImportFormat
val sequenceNumber = brainKey.sequenceNumber val sequenceNumber = brainKey.sequenceNumber
val encryptedBrainKey = CryptoUtils.encrypt(context!!, brainKeyWords) val encryptedBrainKey = CryptoUtils.encrypt(requireContext(), brainKeyWords)
val encryptedSequenceNumber = CryptoUtils.encrypt(context!!, sequenceNumber.toString()) val encryptedSequenceNumber =
val encryptedWIF = CryptoUtils.encrypt(context!!, wif) CryptoUtils.encrypt(requireContext(), sequenceNumber.toString())
val encryptedWIF = CryptoUtils.encrypt(requireContext(), wif)
val authority = Authority(0, userId, authorityType, encryptedWIF, encryptedBrainKey, encryptedSequenceNumber) val authority = Authority(
0,
userId,
authorityType,
encryptedWIF,
encryptedBrainKey,
encryptedSequenceNumber
)
val authorityRepository = AuthorityRepository(context!!) val authorityRepository = AuthorityRepository(requireContext())
authorityRepository.insert(authority) authorityRepository.insert(authority)
} }
} }

View file

@ -362,8 +362,9 @@ class CreateAccountFragment : BaseAccountFragment() {
var reader: BufferedReader? = null var reader: BufferedReader? = null
val dictionary: String val dictionary: String
try { try {
reader = reader = BufferedReader(
BufferedReader(InputStreamReader(context!!.assets.open(BRAINKEY_FILE), "UTF-8")) InputStreamReader(requireContext().assets.open(BRAINKEY_FILE), "UTF-8")
)
dictionary = reader.readLine() dictionary = reader.readLine()
val brainKeySuggestion = BrainKey.suggest(dictionary) val brainKeySuggestion = BrainKey.suggest(dictionary)

View file

@ -12,8 +12,7 @@ import android.view.*
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
@ -38,12 +37,13 @@ class EReceiptFragment : Fragment() {
private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100 private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100
} }
private val args: EReceiptFragmentArgs by navArgs()
private val viewModel: EReceiptViewModel by viewModels()
private var _binding: FragmentEReceiptBinding? = null private var _binding: FragmentEReceiptBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private val args: EReceiptFragmentArgs by navArgs()
private lateinit var mEReceiptViewModel: EReceiptViewModel
private lateinit var mLocale: Locale private lateinit var mLocale: Locale
override fun onCreateView( override fun onCreateView(
@ -75,10 +75,7 @@ class EReceiptFragment : Fragment() {
val transferId = args.transferId val transferId = args.transferId
mEReceiptViewModel = ViewModelProviders.of(this).get(EReceiptViewModel::class.java) viewModel.get(userId, transferId).observe(viewLifecycleOwner, { transferDetail ->
mEReceiptViewModel.get(userId, transferId)
.observe(this, Observer<TransferDetail> { transferDetail ->
bindTransferDetail(transferDetail) bindTransferDetail(transferDetail)
}) })
} }
@ -165,7 +162,7 @@ class EReceiptFragment : Fragment() {
* shares it but if it is not then it asks the user for that permission */ * shares it but if it is not then it asks the user for that permission */
private fun verifyStoragePermission() { private fun verifyStoragePermission() {
if (ContextCompat if (ContextCompat
.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) .checkSelfPermission(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED != PackageManager.PERMISSION_GRANTED
) { ) {
// Permission is not already granted // Permission is not already granted

View file

@ -10,8 +10,7 @@ import android.widget.TextView
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.adapters.BalancesDetailsAdapter import cy.agorise.bitsybitshareswallet.adapters.BalancesDetailsAdapter
@ -42,6 +41,8 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen
const val END_DATE_PICKER = 1 const val END_DATE_PICKER = 1
} }
private val viewModel: BalanceDetailViewModel by viewModels()
private var _binding: DialogFilterOptionsBinding? = null private var _binding: DialogFilterOptionsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
@ -56,8 +57,6 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen
private var mBalanceDetails = ArrayList<BalanceDetail>() private var mBalanceDetails = ArrayList<BalanceDetail>()
private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel
private var mBalancesDetailsAdapter: BalancesDetailsAdapter? = null private var mBalancesDetailsAdapter: BalancesDetailsAdapter? = null
private lateinit var mCurrency: Currency private lateinit var mCurrency: Currency
@ -117,7 +116,7 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
onAttachToParentFragment(parentFragment!!) onAttachToParentFragment(requireParentFragment())
val crashlytics = FirebaseCrashlytics.getInstance() val crashlytics = FirebaseCrashlytics.getInstance()
crashlytics.setCustomKey(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG) crashlytics.setCustomKey(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG)
@ -150,18 +149,12 @@ class FilterOptionsDialog : DialogFragment(), DatePickerFragment.OnDateSetListen
binding.cbAsset.isChecked = mFilterOptions.assetAll binding.cbAsset.isChecked = mFilterOptions.assetAll
// Configure BalanceDetailViewModel to obtain the user's Balances // Configure BalanceDetailViewModel to obtain the user's Balances
mBalanceDetailViewModel = viewModel.getAll().observe(viewLifecycleOwner, { balancesDetails ->
ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java)
mBalanceDetailViewModel.getAll()
.observe(this, Observer<List<BalanceDetail>> { balancesDetails ->
mBalanceDetails.clear() mBalanceDetails.clear()
mBalanceDetails.addAll(balancesDetails) mBalanceDetails.addAll(balancesDetails)
mBalanceDetails.sortWith( mBalanceDetails.sortWith { a, b -> a.toString().compareTo(b.toString(), true) }
Comparator { a, b -> a.toString().compareTo(b.toString(), true) }
)
mBalancesDetailsAdapter = BalancesDetailsAdapter( mBalancesDetailsAdapter = BalancesDetailsAdapter(
context!!, requireContext(),
android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_item,
mBalanceDetails mBalanceDetails
) )

View file

@ -6,16 +6,15 @@ import android.view.*
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter import androidx.fragment.app.FragmentPagerAdapter
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.database.entities.UserAccount
import cy.agorise.bitsybitshareswallet.databinding.FragmentHomeBinding import cy.agorise.bitsybitshareswallet.databinding.FragmentHomeBinding
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.viewmodels.UserAccountViewModel import cy.agorise.bitsybitshareswallet.viewmodels.UserAccountViewModel
@ -27,11 +26,11 @@ class HomeFragment : Fragment() {
private const val TAG = "HomeFragment" private const val TAG = "HomeFragment"
} }
private val viewModel: UserAccountViewModel by viewModels()
private var _binding: FragmentHomeBinding? = null private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var mUserAccountViewModel: UserAccountViewModel
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
@ -47,7 +46,8 @@ class HomeFragment : Fragment() {
// MerchantsFragment (visibility) // MerchantsFragment (visibility)
val toolbar: Toolbar? = activity?.findViewById(R.id.toolbar) val toolbar: Toolbar? = activity?.findViewById(R.id.toolbar)
(activity as AppCompatActivity).setSupportActionBar(toolbar) (activity as AppCompatActivity).setSupportActionBar(toolbar)
toolbar?.navigationIcon = resources.getDrawable(R.drawable.ic_bitsy_logo_2, null) toolbar?.navigationIcon =
ResourcesCompat.getDrawable(resources, R.drawable.ic_bitsy_logo_2, null)
toolbar?.setBackgroundResource(if (!nightMode) R.color.colorPrimary else R.color.colorToolbarDark) toolbar?.setBackgroundResource(if (!nightMode) R.color.colorPrimary else R.color.colorToolbarDark)
toolbar?.visibility = View.VISIBLE toolbar?.visibility = View.VISIBLE
toolbar?.title = getString(R.string.app_name) toolbar?.title = getString(R.string.app_name)
@ -94,10 +94,7 @@ class HomeFragment : Fragment() {
} }
// Configure UserAccountViewModel to show the current account // Configure UserAccountViewModel to show the current account
mUserAccountViewModel = ViewModelProviders.of(this).get(UserAccountViewModel::class.java) viewModel.getUserAccount(userId).observe(viewLifecycleOwner, { userAccount ->
mUserAccountViewModel.getUserAccount(userId)
.observe(this, Observer<UserAccount> { userAccount ->
if (userAccount != null) { if (userAccount != null) {
binding.tvAccountName.text = userAccount.name binding.tvAccountName.text = userAccount.name
if (userAccount.isLtm) { if (userAccount.isLtm) {
@ -149,11 +146,11 @@ class HomeFragment : Fragment() {
} }
override fun getPageTitle(position: Int): CharSequence { override fun getPageTitle(position: Int): CharSequence {
return listOf( return when (position) {
getString(R.string.title_balances), 0 -> getString(R.string.title_balances)
getString(R.string.title_net_worth), 1 -> getString(R.string.title_net_worth)
"" else -> ""
)[position] }
} }
override fun getCount(): Int { override fun getCount(): Int {

View file

@ -402,7 +402,7 @@ class ImportBrainkeyFragment : BaseAccountFragment() {
for (accountProperties in accountPropertiesList) { for (accountProperties in accountPropertiesList) {
candidates.add(accountProperties.name) candidates.add(accountProperties.name)
} }
MaterialDialog(context!!) MaterialDialog(requireContext())
.title(R.string.dialog__account_candidates_title) .title(R.string.dialog__account_candidates_title)
.message(R.string.dialog__account_candidates_content) .message(R.string.dialog__account_candidates_content)
.listItemsSingleChoice( .listItemsSingleChoice(

View file

@ -18,8 +18,7 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.cursoradapter.widget.SimpleCursorAdapter import androidx.cursoradapter.widget.SimpleCursorAdapter
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView import com.afollestad.materialdialogs.customview.customView
import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.CameraUpdateFactory
@ -73,13 +72,13 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
private const val SUGGEST_COLUMN_IMAGE_RESOURCE = "suggest_image_resource" private const val SUGGEST_COLUMN_IMAGE_RESOURCE = "suggest_image_resource"
} }
private val viewModel: MerchantViewModel by viewModels()
private var _binding: FragmentMerchantsBinding? = null private var _binding: FragmentMerchantsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private var mMap: GoogleMap? = null private var mMap: GoogleMap? = null
private lateinit var mMerchantViewModel: MerchantViewModel
private var mMarkerManager: MarkerManager? = null private var mMarkerManager: MarkerManager? = null
/** Keeps track of all RxJava disposables, to make sure they are all disposed when the fragment is destroyed */ /** Keeps track of all RxJava disposables, to make sure they are all disposed when the fragment is destroyed */
@ -166,8 +165,6 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this) mapFragment.getMapAsync(this)
mMerchantViewModel = ViewModelProviders.of(this).get(MerchantViewModel::class.java)
setupPopupWindow() setupPopupWindow()
// Gets the screen width to correctly place the merchants and tellers popup menu // Gets the screen width to correctly place the merchants and tellers popup menu
@ -245,12 +242,12 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
private fun updateSearchViewSuggestions(query: String) { private fun updateSearchViewSuggestions(query: String) {
// Obtain observable of the list of merchants matching the query // Obtain observable of the list of merchants matching the query
val merchantsObs = mMerchantViewModel.queryMerchants(query) val merchantsObs = viewModel.queryMerchants(query)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).toObservable() .observeOn(AndroidSchedulers.mainThread()).toObservable()
// Obtain observable of the list of tellers matching the query // Obtain observable of the list of tellers matching the query
val tellerObs = mMerchantViewModel.queryTellers(query) val tellerObs = viewModel.queryTellers(query)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).toObservable() .observeOn(AndroidSchedulers.mainThread()).toObservable()
@ -449,7 +446,10 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
} }
private fun verifyLocationPermission() { private fun verifyLocationPermission() {
if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.ACCESS_FINE_LOCATION) if (ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED != PackageManager.PERMISSION_GRANTED
) { ) {
// Permission is not already granted // Permission is not already granted
@ -482,7 +482,7 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
// Force marker to use a custom info window // Force marker to use a custom info window
mMerchantClusterManager?.markerCollection?.setOnInfoWindowAdapter(MerchantInfoWindowAdapter()) mMerchantClusterManager?.markerCollection?.setOnInfoWindowAdapter(MerchantInfoWindowAdapter())
mMerchantViewModel.getAllMerchants().observe(this, Observer<List<Merchant>> { merchants -> viewModel.getAllMerchants().observe(viewLifecycleOwner, { merchants ->
this.merchants.clear() this.merchants.clear()
this.merchants.addAll(merchants) this.merchants.addAll(merchants)
showHideMerchantsMarkers() showHideMerchantsMarkers()
@ -508,7 +508,7 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
// Force marker to use a custom info window // Force marker to use a custom info window
mTellerClusterManager?.markerCollection?.setOnInfoWindowAdapter(TellerInfoWindowAdapter()) mTellerClusterManager?.markerCollection?.setOnInfoWindowAdapter(TellerInfoWindowAdapter())
mMerchantViewModel.getAllTellers().observe(this, Observer<List<Teller>> { tellers -> viewModel.getAllTellers().observe(viewLifecycleOwner, { tellers ->
this.tellers.clear() this.tellers.clear()
this.tellers.addAll(tellers) this.tellers.addAll(tellers)
showHideTellersMarkers() showHideTellersMarkers()

View file

@ -11,8 +11,7 @@ import android.widget.AdapterView
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import com.google.common.primitives.UnsignedLong import com.google.common.primitives.UnsignedLong
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.jakewharton.rxbinding3.widget.textChanges import com.jakewharton.rxbinding3.widget.textChanges
@ -52,11 +51,11 @@ class ReceiveTransactionFragment : ConnectedFragment() {
private const val OTHER_ASSET = "other_asset" private const val OTHER_ASSET = "other_asset"
} }
private val viewModel: ReceiveTransactionViewModel by viewModels()
private var _binding: FragmentReceiveTransactionBinding? = null private var _binding: FragmentReceiveTransactionBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var mViewModel: ReceiveTransactionViewModel
/** Current user account */ /** Current user account */
private var mUserAccount: UserAccount? = null private var mUserAccount: UserAccount? = null
@ -118,18 +117,14 @@ class ReceiveTransactionFragment : ConnectedFragment() {
crashlytics.setCustomKey(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG) crashlytics.setCustomKey(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG)
// Configure ViewModel // Configure ViewModel
mViewModel = ViewModelProviders.of(this).get(ReceiveTransactionViewModel::class.java)
val userId = PreferenceManager.getDefaultSharedPreferences(context) val userId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") .getString(Constants.KEY_CURRENT_ACCOUNT_ID, "")
mViewModel.getUserAccount(userId!!).observe(this, viewModel.getUserAccount(userId!!).observe(viewLifecycleOwner, { user ->
Observer<cy.agorise.bitsybitshareswallet.database.entities.UserAccount> { user ->
mUserAccount = UserAccount(user.id, user.name) mUserAccount = UserAccount(user.id, user.name)
}) })
mViewModel.getAllNonZero().observe(this, viewModel.getAllNonZero().observe(viewLifecycleOwner, { assets ->
Observer<List<cy.agorise.bitsybitshareswallet.database.entities.Asset>> { assets ->
mAssets.clear() mAssets.clear()
mAssets.addAll(assets) mAssets.addAll(assets)
@ -152,7 +147,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
mAssets.add(asset) mAssets.add(asset)
mAssetsAdapter = mAssetsAdapter =
AssetsAdapter(context!!, android.R.layout.simple_spinner_item, mAssets) AssetsAdapter(requireContext(), android.R.layout.simple_spinner_item, mAssets)
binding.spAsset.adapter = mAssetsAdapter binding.spAsset.adapter = mAssetsAdapter
// Try to select the selectedAssetSymbol // Try to select the selectedAssetSymbol
@ -164,7 +159,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
} }
}) })
mViewModel.qrCodeBitmap.observe(this, Observer { bitmap -> viewModel.qrCodeBitmap.observe(viewLifecycleOwner, { bitmap ->
binding.ivQR.setImageBitmap(bitmap) binding.ivQR.setImageBitmap(bitmap)
}) })
@ -204,7 +199,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
// Add adapter to the Assets AutoCompleteTextView // Add adapter to the Assets AutoCompleteTextView
mAutoSuggestAssetAdapter = mAutoSuggestAssetAdapter =
AutoSuggestAssetAdapter(context!!, android.R.layout.simple_dropdown_item_1line) AutoSuggestAssetAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line)
binding.actvAsset.setAdapter(mAutoSuggestAssetAdapter) binding.actvAsset.setAdapter(mAutoSuggestAssetAdapter)
// Use RxJava Debounce to avoid making calls to the NetworkService on every text change event and also avoid // Use RxJava Debounce to avoid making calls to the NetworkService on every text change event and also avoid
@ -311,7 +306,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
) )
Log.d(TAG, "invoice: " + invoice.toJsonString()) Log.d(TAG, "invoice: " + invoice.toJsonString())
try { try {
mViewModel.updateInvoice(invoice, min(binding.ivQR.width, binding.ivQR.height)) viewModel.updateInvoice(invoice, min(binding.ivQR.width, binding.ivQR.height))
updateAmountAddressUI(amount, asset.symbol, asset.precision, mUserAccount!!.name) updateAmountAddressUI(amount, asset.symbol, asset.precision, mUserAccount!!.name)
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
Log.e(TAG, "NullPointerException. Msg: " + e.message) Log.e(TAG, "NullPointerException. Msg: " + e.message)
@ -366,7 +361,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
private fun verifyStoragePermission() { private fun verifyStoragePermission() {
if (ContextCompat.checkSelfPermission( if (ContextCompat.checkSelfPermission(
activity!!, requireActivity(),
android.Manifest.permission.WRITE_EXTERNAL_STORAGE android.Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
!= PackageManager.PERMISSION_GRANTED != PackageManager.PERMISSION_GRANTED
@ -411,7 +406,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
// Get Screenshot // Get Screenshot
val screenshot = Helper.loadBitmapFromView(binding.container) val screenshot = Helper.loadBitmapFromView(binding.container)
val imageUri = Helper.saveTemporalBitmap(context!!, screenshot) val imageUri = Helper.saveTemporalBitmap(requireContext(), screenshot)
// Prepare information for share intent // Prepare information for share intent
val subject = getString(R.string.msg__invoice_subject, mUserAccount?.name) val subject = getString(R.string.msg__invoice_subject, mUserAccount?.name)

View file

@ -12,8 +12,7 @@ import android.widget.Toast
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
@ -74,13 +73,15 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
private const val ACTION_SEND_TRANSFER = 1 private const val ACTION_SEND_TRANSFER = 1
} }
private var _binding: FragmentSendTransactionBinding? = null
private val binding get() = _binding!!
// Navigation AAC Safe Args
private val args: SendTransactionFragmentArgs by navArgs() private val args: SendTransactionFragmentArgs by navArgs()
private lateinit var mViewModel: SendTransactionViewModel // TODO consolidate ViewModels
private val viewModel: SendTransactionViewModel by viewModels()
private val balanceDetailViewModel: BalanceDetailViewModel by viewModels()
private var _binding: FragmentSendTransactionBinding? = null
private val binding get() = _binding!!
/** Variables used in field's validation */ /** Variables used in field's validation */
private var isCameraPreviewVisible = false private var isCameraPreviewVisible = false
@ -90,8 +91,6 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
private var mBalancesDetails = ArrayList<BalanceDetail>() private var mBalancesDetails = ArrayList<BalanceDetail>()
private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel
private var mBalancesDetailsAdapter: BalancesDetailsAdapter? = null private var mBalancesDetailsAdapter: BalancesDetailsAdapter? = null
/** Keeps track of the asset's symbol selected in the Asset spinner */ /** Keeps track of the asset's symbol selected in the Asset spinner */
@ -162,10 +161,8 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
mUserAccount = UserAccount(userId) mUserAccount = UserAccount(userId)
// Configure ViewModel // Configure ViewModel
mViewModel = ViewModelProviders.of(this).get(SendTransactionViewModel::class.java) viewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal)
.observe(viewLifecycleOwner, { encryptedWIF ->
mViewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal).observe(this,
Observer<String> { encryptedWIF ->
context?.let { context?.let {
try { try {
wifKey = CryptoUtils.decrypt(it, encryptedWIF) wifKey = CryptoUtils.decrypt(it, encryptedWIF)
@ -186,18 +183,14 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
binding.fabOpenCamera.setOnClickListener { if (isCameraPreviewVisible) stopCameraPreview() else verifyCameraPermission() } binding.fabOpenCamera.setOnClickListener { if (isCameraPreviewVisible) stopCameraPreview() else verifyCameraPermission() }
// Configure BalanceDetailViewModel to show the current balances // Configure BalanceDetailViewModel to show the current balances
mBalanceDetailViewModel = balanceDetailViewModel.getAll().observe(viewLifecycleOwner, { balancesDetails ->
ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java)
mBalanceDetailViewModel.getAll()
.observe(this, Observer<List<BalanceDetail>> { balancesDetails ->
mBalancesDetails.clear() mBalancesDetails.clear()
mBalancesDetails.addAll(balancesDetails) mBalancesDetails.addAll(balancesDetails)
mBalancesDetails.sortWith( mBalancesDetails.sortWith(
Comparator { a, b -> a.toString().compareTo(b.toString(), true) } Comparator { a, b -> a.toString().compareTo(b.toString(), true) }
) )
mBalancesDetailsAdapter = BalancesDetailsAdapter( mBalancesDetailsAdapter = BalancesDetailsAdapter(
context!!, requireContext(),
android.R.layout.simple_spinner_item, android.R.layout.simple_spinner_item,
mBalancesDetails mBalancesDetails
) )
@ -387,7 +380,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
/** Verifies if the user has already granted the Camera permission, if not the asks for it */ /** Verifies if the user has already granted the Camera permission, if not the asks for it */
private fun verifyCameraPermission() { private fun verifyCameraPermission() {
if (ContextCompat.checkSelfPermission(activity!!, android.Manifest.permission.CAMERA) if (ContextCompat.checkSelfPermission(requireActivity(), android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED != PackageManager.PERMISSION_GRANTED
) { ) {
// Permission is not already granted // Permission is not already granted
@ -711,7 +704,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_info) { if (item.itemId == R.id.menu_info) {
MaterialDialog(context!!).show { MaterialDialog(requireContext()).show {
customView(R.layout.dialog_send_transaction_info, scrollable = true) customView(R.layout.dialog_send_transaction_info, scrollable = true)
positiveButton(android.R.string.ok) { dismiss() } positiveButton(android.R.string.ok) { dismiss() }
} }

View file

@ -11,7 +11,7 @@ import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.ViewModelProviders import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.callbacks.onDismiss import com.afollestad.materialdialogs.callbacks.onDismiss
@ -60,11 +60,11 @@ class SettingsFragment : ConnectedFragment(), BaseSecurityLockDialog.OnPINPatter
private const val RESPONSE_BROADCAST_TRANSACTION = 3 private const val RESPONSE_BROADCAST_TRANSACTION = 3
} }
private val viewModel: SettingsFragmentViewModel by viewModels()
private var _binding: FragmentSettingsBinding? = null private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var mViewModel: SettingsFragmentViewModel
private var mUserAccount: UserAccount? = null private var mUserAccount: UserAccount? = null
private var privateKey: String? = null private var privateKey: String? = null
@ -119,10 +119,7 @@ class SettingsFragment : ConnectedFragment(), BaseSecurityLockDialog.OnPINPatter
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: "" .getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
// Configure ViewModel // Configure ViewModel
mViewModel = ViewModelProviders.of(this).get(SettingsFragmentViewModel::class.java) viewModel.getUserAccount(userId).observe(viewLifecycleOwner, { userAccount ->
mViewModel.getUserAccount(userId).observe(this,
androidx.lifecycle.Observer<cy.agorise.bitsybitshareswallet.database.entities.UserAccount> { userAccount ->
if (userAccount != null) { if (userAccount != null) {
mUserAccount = UserAccount(userAccount.id, userAccount.name) mUserAccount = UserAccount(userAccount.id, userAccount.name)
binding.btnUpgradeToLTM.isEnabled = binding.btnUpgradeToLTM.isEnabled =
@ -130,8 +127,8 @@ class SettingsFragment : ConnectedFragment(), BaseSecurityLockDialog.OnPINPatter
} }
}) })
mViewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal).observe(this, viewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal)
androidx.lifecycle.Observer<String> { encryptedWIF -> .observe(viewLifecycleOwner, { encryptedWIF ->
context?.let { context?.let {
try { try {
privateKey = CryptoUtils.decrypt(it, encryptedWIF) privateKey = CryptoUtils.decrypt(it, encryptedWIF)
@ -624,7 +621,7 @@ class SettingsFragment : ConnectedFragment(), BaseSecurityLockDialog.OnPINPatter
private fun removeAccount(context: Context) { private fun removeAccount(context: Context) {
// Clears the database. // Clears the database.
mViewModel.clearDatabase(context) viewModel.clearDatabase(context)
// Clears the shared preferences. // Clears the shared preferences.
val pref = PreferenceManager.getDefaultSharedPreferences(context) val pref = PreferenceManager.getDefaultSharedPreferences(context)

View file

@ -11,8 +11,7 @@ import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsMultiChoice import com.afollestad.materialdialogs.list.listItemsMultiChoice
@ -20,7 +19,6 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.jakewharton.rxbinding3.appcompat.queryTextChangeEvents import com.jakewharton.rxbinding3.appcompat.queryTextChangeEvents
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.adapters.TransfersDetailsAdapter import cy.agorise.bitsybitshareswallet.adapters.TransfersDetailsAdapter
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
import cy.agorise.bitsybitshareswallet.databinding.FragmentTransactionsBinding import cy.agorise.bitsybitshareswallet.databinding.FragmentTransactionsBinding
import cy.agorise.bitsybitshareswallet.models.FilterOptions import cy.agorise.bitsybitshareswallet.models.FilterOptions
import cy.agorise.bitsybitshareswallet.utils.* import cy.agorise.bitsybitshareswallet.utils.*
@ -42,11 +40,11 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100 private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100
} }
private val viewModel: TransactionsViewModel by viewModels()
private var _binding: FragmentTransactionsBinding? = null private var _binding: FragmentTransactionsBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var mViewModel: TransactionsViewModel
private var mDisposables = CompositeDisposable() private var mDisposables = CompositeDisposable()
override fun onCreateView( override fun onCreateView(
@ -74,15 +72,12 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
val userId = PreferenceManager.getDefaultSharedPreferences(context) val userId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: "" .getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
val transfersDetailsAdapter = TransfersDetailsAdapter(context!!) val transfersDetailsAdapter = TransfersDetailsAdapter(requireContext())
binding.rvTransactions.adapter = transfersDetailsAdapter binding.rvTransactions.adapter = transfersDetailsAdapter
binding.rvTransactions.layoutManager = LinearLayoutManager(context) binding.rvTransactions.layoutManager = LinearLayoutManager(context)
// Configure TransactionsViewModel to fetch the transaction history // Configure TransactionsViewModel to fetch the transaction history
mViewModel = ViewModelProviders.of(this).get(TransactionsViewModel::class.java) viewModel.getFilteredTransactions(userId).observe(viewLifecycleOwner, { transactions ->
mViewModel.getFilteredTransactions(userId).observe(this,
Observer<List<TransferDetail>> { transactions ->
if (transactions.isEmpty()) { if (transactions.isEmpty()) {
binding.rvTransactions.visibility = View.GONE binding.rvTransactions.visibility = View.GONE
binding.tvEmpty.visibility = View.VISIBLE binding.tvEmpty.visibility = View.VISIBLE
@ -118,7 +113,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
.map { it.queryText.toString().toLowerCase() } .map { it.queryText.toString().toLowerCase() }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
mViewModel.setFilterQuery(it) viewModel.setFilterQuery(it)
} }
) )
@ -133,7 +128,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
val args = Bundle() val args = Bundle()
args.putParcelable( args.putParcelable(
FilterOptionsDialog.KEY_FILTER_OPTIONS, FilterOptionsDialog.KEY_FILTER_OPTIONS,
mViewModel.getFilterOptions() viewModel.getFilterOptions()
) )
filterOptionsDialog.arguments = args filterOptionsDialog.arguments = args
filterOptionsDialog.show(childFragmentManager, "filter-options-tag") filterOptionsDialog.show(childFragmentManager, "filter-options-tag")
@ -163,13 +158,13 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
* Gets called when the user selects some filter options in the [FilterOptionsDialog] and wants to apply them. * Gets called when the user selects some filter options in the [FilterOptionsDialog] and wants to apply them.
*/ */
override fun onFilterOptionsSelected(filterOptions: FilterOptions) { override fun onFilterOptionsSelected(filterOptions: FilterOptions) {
mViewModel.applyFilterOptions(filterOptions) viewModel.applyFilterOptions(filterOptions)
} }
/** Verifies that the storage permission has been granted before attempting to generate the export options */ /** Verifies that the storage permission has been granted before attempting to generate the export options */
private fun verifyStoragePermission() { private fun verifyStoragePermission() {
if (ContextCompat.checkSelfPermission( if (ContextCompat.checkSelfPermission(
activity!!, requireActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
!= PackageManager.PERMISSION_GRANTED != PackageManager.PERMISSION_GRANTED
@ -205,7 +200,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
} }
private fun showExportOptionsDialog() { private fun showExportOptionsDialog() {
MaterialDialog(context!!).show { MaterialDialog(requireContext()).show {
title(R.string.title_export_transactions) title(R.string.title_export_transactions)
listItemsMultiChoice( listItemsMultiChoice(
R.array.export_options, R.array.export_options,
@ -228,7 +223,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
return return
} }
mViewModel.getFilteredTransactionsOnce()?.let { filteredTransactions -> viewModel.getFilteredTransactionsOnce()?.let { filteredTransactions ->
if (exportPDF) if (exportPDF)
activity?.let { PDFGeneratorTask(it).execute(filteredTransactions) } activity?.let { PDFGeneratorTask(it).execute(filteredTransactions) }

View file

@ -3,8 +3,8 @@
buildscript { buildscript {
ext { ext {
kotlin_version = '1.4.30' kotlin_version = '1.4.31'
nav_version = '2.1.0' nav_version = '2.3.4'
} }
repositories { repositories {