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.
develop
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 {
def lifecycle_version = "2.2.0"
def lifecycle_version = "2.3.0"
def arch_version = "2.1.0"
def room_version = "2.2.6"
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.maps.android:android-maps-utils:0.5'
// AAC Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" // viewModelScope
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
// AAC Room
implementation "androidx.room:room-runtime:$room_version"

View File

@ -7,10 +7,9 @@ import android.os.Handler
import android.preference.PreferenceManager
import android.util.Log
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.pm.PackageInfoCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.google.firebase.crashlytics.FirebaseCrashlytics
import cy.agorise.bitsybitshareswallet.database.entities.Balance
import cy.agorise.bitsybitshareswallet.database.entities.Transfer
@ -69,10 +68,11 @@ abstract class ConnectedActivity : AppCompatActivity() {
private const val RESPONSE_GET_MARKET_HISTORY = 6
}
private lateinit var mUserAccountViewModel: UserAccountViewModel
private lateinit var mBalanceViewModel: BalanceViewModel
private lateinit var mTransferViewModel: TransferViewModel
private lateinit var mConnectedActivityViewModel: ConnectedActivityViewModel
// TODO consolidate ViewModels
private val userAccountViewModel: UserAccountViewModel by viewModels()
private val balanceViewModel: BalanceViewModel by viewModels()
private val transferViewModel: TransferViewModel by viewModels()
private val connectedActivityViewModel: ConnectedActivityViewModel by viewModels()
private lateinit var mAssetRepository: AssetRepository
@ -114,42 +114,38 @@ abstract class ConnectedActivity : AppCompatActivity() {
mAssetRepository = AssetRepository(this)
// Configure ConnectedActivityViewModel to obtain missing equivalent values
mConnectedActivityViewModel = ViewModelProviders.of(this).get(ConnectedActivityViewModel::class.java)
val currencyCode = Helper.getCoingeckoSupportedCurrency(Locale.getDefault())
Log.d(TAG, "Using currency: ${currencyCode.toUpperCase(Locale.ROOT)}")
mConnectedActivityViewModel.observeMissingEquivalentValuesIn(currencyCode)
connectedActivityViewModel.observeMissingEquivalentValuesIn(currencyCode)
// Configure UserAccountViewModel to obtain the missing account ids
mUserAccountViewModel = ViewModelProviders.of(this).get(UserAccountViewModel::class.java)
mUserAccountViewModel.getMissingUserAccountIds().observe(this, Observer<List<String>>{ userAccountIds ->
userAccountViewModel.getMissingUserAccountIds().observe(this, { userAccountIds ->
if (userAccountIds.isNotEmpty()) {
missingUserAccounts.clear()
for (userAccountId in userAccountIds)
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
mBalanceViewModel = ViewModelProviders.of(this).get(BalanceViewModel::class.java)
mBalanceViewModel.getMissingAssetIds().observe(this, Observer<List<String>>{ assetIds ->
balanceViewModel.getMissingAssetIds().observe(this, { assetIds ->
if (assetIds.isNotEmpty()) {
missingAssets.clear()
for (assetId in assetIds)
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
mTransferViewModel = ViewModelProviders.of(this).get(TransferViewModel::class.java)
mTransferViewModel.getTransferBlockNumberWithMissingTime().observe(this, Observer<Long>{ blockNumber ->
transferViewModel.getTransferBlockNumberWithMissingTime().observe(this, { blockNumber ->
if (blockNumber != null && blockNumber != blockNumberWithMissingTime) {
blockNumberWithMissingTime = blockNumber
mHandler.post(mRequestBlockMissingTimeTask)
@ -167,13 +163,14 @@ abstract class ConnectedActivity : AppCompatActivity() {
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 hasPurgedEquivalentValues = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(Constants.KEY_HAS_PURGED_EQUIVALENT_VALUES, false)
if(versionCode > 11 && !hasPurgedEquivalentValues) {
if (versionCode > 11 && !hasPurgedEquivalentValues) {
thread {
mConnectedActivityViewModel.purgeEquivalentValues()
connectedActivityViewModel.purgeEquivalentValues()
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.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
* incoming data.
*/
private fun handleError(throwable: Throwable){
private fun handleError(throwable: Throwable) {
Log.e(TAG, "Error while processing received message. Msg: " + throwable.message)
val stack = throwable.stackTrace
for (e in stack) {
@ -217,24 +214,24 @@ abstract class ConnectedActivity : AppCompatActivity() {
if (message.error == null) {
if (responseMap.containsKey(message.id)) {
when (responseMap[message.id]) {
RESPONSE_GET_FULL_ACCOUNTS ->
RESPONSE_GET_FULL_ACCOUNTS ->
handleAccountDetails((message.result as List<*>)[0] as FullAccountDetails)
RESPONSE_GET_ACCOUNTS ->
RESPONSE_GET_ACCOUNTS ->
handleAccountProperties(message.result as List<AccountProperties>)
RESPONSE_GET_ACCOUNT_BALANCES ->
RESPONSE_GET_ACCOUNT_BALANCES ->
handleBalanceUpdate(message.result as List<AssetAmount>)
RESPONSE_GET_ASSETS ->
RESPONSE_GET_ASSETS ->
handleAssets(message.result as List<Asset>)
RESPONSE_GET_BLOCK_HEADER -> {
RESPONSE_GET_BLOCK_HEADER -> {
val blockNumber = requestIdToBlockNumberMap[message.id] ?: 0L
handleBlockHeader(message.result as BlockHeader, blockNumber)
requestIdToBlockNumberMap.remove(message.id)
}
RESPONSE_GET_MARKET_HISTORY -> handleMarketData(message.result as List<BucketObject>)
RESPONSE_GET_MARKET_HISTORY -> handleMarketData(message.result as List<BucketObject>)
}
responseMap.remove(message.id)
}
@ -259,11 +256,11 @@ abstract class ConnectedActivity : AppCompatActivity() {
responseMap.clear()
} else if (message.updateCode == ConnectionStatusUpdate.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
mTransferViewModel
.getTransfersWithMissingBtsValue().observe(this, Observer<Transfer> {
if(it != null) handleTransfersWithMissingBtsValue(it)
transferViewModel
.getTransfersWithMissingBtsValue().observe(this, {
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.
*/
private fun handleTransfersWithMissingBtsValue(transfer: Transfer) {
if(mNetworkService?.isConnected == true){
if (mNetworkService?.isConnected == true) {
val base = Asset(transfer.transferAssetId)
val quote = Asset("1.3.0")
val bucket: Long = TimeUnit.SECONDS.convert(1, TimeUnit.DAYS)
val end: Long = transfer.timestamp * 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
this.transfer = transfer
}
@ -292,11 +292,17 @@ abstract class ConnectedActivity : AppCompatActivity() {
*/
private fun handleAccountDetails(accountDetails: FullAccountDetails) {
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) {
Log.d(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.")
Log.d(
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()
} else if (storedOpCount == -1L) {
// 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
*/
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) {
val userAccount = cy.agorise.bitsybitshareswallet.database.entities.UserAccount(
@ -329,7 +336,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
userAccounts.add(userAccount)
}
mUserAccountViewModel.insertAll(userAccounts)
userAccountViewModel.insertAll(userAccounts)
missingUserAccounts.clear()
}
@ -346,7 +353,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
balances.add(balance)
}
mBalanceViewModel.insertAll(balances)
balanceViewModel.insertAll(balances)
}
/**
@ -382,35 +389,38 @@ abstract class ConnectedActivity : AppCompatActivity() {
try {
val date = dateFormat.parse(blockHeader.timestamp)
mTransferViewModel.setBlockTime(blockNumber, date.time / 1000)
transferViewModel.setBlockTime(blockNumber, date.time / 1000)
} catch (e: ParseException) {
Log.e(TAG, "ParseException. Msg: " + e.message)
}
}
private fun handleMarketData(buckets: List<BucketObject>) {
if(buckets.isNotEmpty()){
Log.d(TAG,"handleMarketData. Bucket is not empty")
if (buckets.isNotEmpty()) {
Log.d(TAG, "handleMarketData. Bucket is not empty")
val bucket = buckets[0]
val pair = Pair(transfer, bucket)
val disposable = Observable.just(pair)
.subscribeOn(Schedulers.computation())
.map { mTransferViewModel.updateBtsValue(it.first!!, it.second) }
.subscribe({},{
Log.e(TAG,"Error at updateBtsValue. Msg: ${it.message}")
for(line in it.stackTrace) Log.e(TAG, "${line.className}#${line.methodName}:${line.lineNumber}")
.map { transferViewModel.updateBtsValue(it.first!!, it.second) }
.subscribe({}, {
Log.e(TAG, "Error at updateBtsValue. Msg: ${it.message}")
for (line in it.stackTrace)
Log.e(TAG, "${line.className}#${line.methodName}:${line.lineNumber}")
})
mCompositeDisposable.add(disposable)
}else{
Log.i(TAG,"handleMarketData. Bucket IS empty")
AsyncTask.execute { mTransferViewModel.updateBtsValue(transfer!!, Transfer.ERROR) }
} else {
Log.i(TAG, "handleMarketData. Bucket IS empty")
AsyncTask.execute { transferViewModel.updateBtsValue(transfer!!, Transfer.ERROR) }
}
}
private fun updateBalances() {
if (mNetworkService?.isConnected == true) {
val id = mNetworkService!!.sendMessage(GetAccountBalances(mCurrentAccount, ArrayList()),
GetAccountBalances.REQUIRED_API)
val id = mNetworkService!!.sendMessage(
GetAccountBalances(mCurrentAccount, ArrayList()),
GetAccountBalances.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_ACCOUNT_BALANCES
}
@ -447,10 +457,13 @@ abstract class ConnectedActivity : AppCompatActivity() {
private val mRequestMissingUserAccountsTask = object : Runnable {
override fun run() {
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
} else if (missingUserAccounts.isNotEmpty()){
} else if (missingUserAccounts.isNotEmpty()) {
mHandler.postDelayed(this, Constants.NETWORK_SERVICE_RETRY_PERIOD)
}
}
@ -462,10 +475,11 @@ abstract class ConnectedActivity : AppCompatActivity() {
private val mRequestMissingAssetsTask = object : Runnable {
override fun run() {
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
} else if (missingAssets.isNotEmpty()){
} else if (missingAssets.isNotEmpty()) {
mHandler.postDelayed(this, Constants.NETWORK_SERVICE_RETRY_PERIOD)
}
}
@ -480,13 +494,17 @@ abstract class ConnectedActivity : AppCompatActivity() {
if (mCurrentAccount != null) {
val userAccounts = ArrayList<String>()
userAccounts.add(mCurrentAccount!!.objectId)
val id = mNetworkService!!.sendMessage(GetFullAccounts(userAccounts, false),
GetFullAccounts.REQUIRED_API)
val id = mNetworkService!!.sendMessage(
GetFullAccounts(userAccounts, false),
GetFullAccounts.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_FULL_ACCOUNTS
}
} 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)
@ -500,8 +518,10 @@ abstract class ConnectedActivity : AppCompatActivity() {
override fun run() {
if (mNetworkService?.isConnected == true) {
val id = mNetworkService!!.sendMessage(GetBlockHeader(blockNumberWithMissingTime),
GetBlockHeader.REQUIRED_API)
val id = mNetworkService!!.sendMessage(
GetBlockHeader(blockNumberWithMissingTime),
GetBlockHeader.REQUIRED_API
)
responseMap[id] = RESPONSE_GET_BLOCK_HEADER
requestIdToBlockNumberMap[id] = blockNumberWithMissingTime
@ -521,7 +541,7 @@ abstract class ConnectedActivity : AppCompatActivity() {
override fun onPause() {
super.onPause()
mNetworkService?.nodeLatencyVerifier?.nodeList?.let { nodes ->
mConnectedActivityViewModel.updateNodeLatencies(nodes as List<FullNode>)
connectedActivityViewModel.updateNodeLatencies(nodes as List<FullNode>)
}
mHandler.removeCallbacks(mCheckMissingPaymentsTask)
@ -532,6 +552,6 @@ abstract class ConnectedActivity : AppCompatActivity() {
override fun 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.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import cy.agorise.bitsybitshareswallet.adapters.BalancesAdapter
import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail
import cy.agorise.bitsybitshareswallet.databinding.FragmentBalancesBinding
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
class BalancesFragment : Fragment() {
private val viewModel: BalanceDetailViewModel by viewModels()
private var _binding: FragmentBalancesBinding? = null
private val binding get() = _binding!!
private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -40,19 +38,15 @@ class BalancesFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
// Configure BalanceDetailViewModel to show the current balances
mBalanceDetailViewModel =
ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java)
val balancesAdapter = BalancesAdapter(context!!)
val balancesAdapter = BalancesAdapter(requireContext())
binding.rvBalances.adapter = balancesAdapter
binding.rvBalances.layoutManager = LinearLayoutManager(context!!)
binding.rvBalances.layoutManager = LinearLayoutManager(requireContext())
binding.rvBalances.addItemDecoration(
DividerItemDecoration(context!!, DividerItemDecoration.VERTICAL)
DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL)
)
mBalanceDetailViewModel.getAll()
.observe(this, Observer<List<BalanceDetail>> { balancesDetails ->
balancesAdapter.replaceAll(balancesDetails)
})
viewModel.getAll().observe(viewLifecycleOwner, { balancesDetails ->
balancesAdapter.replaceAll(balancesDetails)
})
}
}

View File

@ -3,6 +3,7 @@ package cy.agorise.bitsybitshareswallet.fragments
import android.preference.PreferenceManager
import androidx.navigation.fragment.findNavController
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.activities.ConnectedActivity
import cy.agorise.bitsybitshareswallet.database.entities.Authority
import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository
import cy.agorise.bitsybitshareswallet.repositories.UserAccountRepository
@ -13,7 +14,6 @@ import cy.agorise.graphenej.BrainKey
import cy.agorise.graphenej.PublicKey
import cy.agorise.graphenej.models.AccountProperties
import org.bitcoinj.core.ECKey
import cy.agorise.bitsybitshareswallet.activities.ConnectedActivity
abstract class BaseAccountFragment : ConnectedFragment() {
@ -36,7 +36,7 @@ abstract class BaseAccountFragment : ConnectedFragment() {
val hashedPIN = CryptoUtils.createSHA256Hash(salt + pin)
// Stores the user selected PIN, hashed
PreferenceManager.getDefaultSharedPreferences(context!!).edit()
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit()
.putString(Constants.KEY_HASHED_PIN_PATTERN, hashedPIN)
.putString(Constants.KEY_PIN_PATTERN_SALT, salt)
.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
val id = accountProperties.id
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)
// 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()
// 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))
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)) {
addAuthorityToDatabase(accountProperties.id, AuthorityType.ACTIVE.ordinal, mBrainKey!!)
addAuthorityToDatabase(
accountProperties.id,
AuthorityType.ACTIVE.ordinal,
mBrainKey!!
)
}
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 sequenceNumber = brainKey.sequenceNumber
val encryptedBrainKey = CryptoUtils.encrypt(context!!, brainKeyWords)
val encryptedSequenceNumber = CryptoUtils.encrypt(context!!, sequenceNumber.toString())
val encryptedWIF = CryptoUtils.encrypt(context!!, wif)
val encryptedBrainKey = CryptoUtils.encrypt(requireContext(), brainKeyWords)
val encryptedSequenceNumber =
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)
}
}

View File

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

View File

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

View File

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

View File

@ -6,16 +6,15 @@ import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.fragment.app.viewModels
import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController
import com.google.firebase.crashlytics.FirebaseCrashlytics
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.database.entities.UserAccount
import cy.agorise.bitsybitshareswallet.databinding.FragmentHomeBinding
import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.viewmodels.UserAccountViewModel
@ -27,11 +26,11 @@ class HomeFragment : Fragment() {
private const val TAG = "HomeFragment"
}
private val viewModel: UserAccountViewModel by viewModels()
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
private lateinit var mUserAccountViewModel: UserAccountViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -47,7 +46,8 @@ class HomeFragment : Fragment() {
// MerchantsFragment (visibility)
val toolbar: Toolbar? = activity?.findViewById(R.id.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?.visibility = View.VISIBLE
toolbar?.title = getString(R.string.app_name)
@ -94,22 +94,19 @@ class HomeFragment : Fragment() {
}
// Configure UserAccountViewModel to show the current account
mUserAccountViewModel = ViewModelProviders.of(this).get(UserAccountViewModel::class.java)
mUserAccountViewModel.getUserAccount(userId)
.observe(this, Observer<UserAccount> { userAccount ->
if (userAccount != null) {
binding.tvAccountName.text = userAccount.name
if (userAccount.isLtm) {
// Add the lightning bolt to the start of the account name if it is LTM
binding.tvAccountName.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_ltm_account, 0, 0, 0
)
// Add some padding so that the lightning bolt icon is not too close to the account name text
binding.tvAccountName.compoundDrawablePadding = 12
}
viewModel.getUserAccount(userId).observe(viewLifecycleOwner, { userAccount ->
if (userAccount != null) {
binding.tvAccountName.text = userAccount.name
if (userAccount.isLtm) {
// Add the lightning bolt to the start of the account name if it is LTM
binding.tvAccountName.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_ltm_account, 0, 0, 0
)
// Add some padding so that the lightning bolt icon is not too close to the account name text
binding.tvAccountName.compoundDrawablePadding = 12
}
})
}
})
// Navigate to the Receive Transaction Fragment
binding.fabReceiveTransaction.setOnClickListener(
@ -149,11 +146,11 @@ class HomeFragment : Fragment() {
}
override fun getPageTitle(position: Int): CharSequence {
return listOf(
getString(R.string.title_balances),
getString(R.string.title_net_worth),
""
)[position]
return when (position) {
0 -> getString(R.string.title_balances)
1 -> getString(R.string.title_net_worth)
else -> ""
}
}
override fun getCount(): Int {

View File

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

View File

@ -18,8 +18,7 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.cursoradapter.widget.SimpleCursorAdapter
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.fragment.app.viewModels
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
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 val viewModel: MerchantViewModel by viewModels()
private var _binding: FragmentMerchantsBinding? = null
private val binding get() = _binding!!
private var mMap: GoogleMap? = null
private lateinit var mMerchantViewModel: MerchantViewModel
private var mMarkerManager: MarkerManager? = null
/** 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
mapFragment.getMapAsync(this)
mMerchantViewModel = ViewModelProviders.of(this).get(MerchantViewModel::class.java)
setupPopupWindow()
// 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) {
// Obtain observable of the list of merchants matching the query
val merchantsObs = mMerchantViewModel.queryMerchants(query)
val merchantsObs = viewModel.queryMerchants(query)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).toObservable()
// Obtain observable of the list of tellers matching the query
val tellerObs = mMerchantViewModel.queryTellers(query)
val tellerObs = viewModel.queryTellers(query)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()).toObservable()
@ -449,7 +446,10 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
}
private fun verifyLocationPermission() {
if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.ACCESS_FINE_LOCATION)
if (ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.ACCESS_FINE_LOCATION
)
!= PackageManager.PERMISSION_GRANTED
) {
// Permission is not already granted
@ -482,7 +482,7 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
// Force marker to use a custom info window
mMerchantClusterManager?.markerCollection?.setOnInfoWindowAdapter(MerchantInfoWindowAdapter())
mMerchantViewModel.getAllMerchants().observe(this, Observer<List<Merchant>> { merchants ->
viewModel.getAllMerchants().observe(viewLifecycleOwner, { merchants ->
this.merchants.clear()
this.merchants.addAll(merchants)
showHideMerchantsMarkers()
@ -508,7 +508,7 @@ class MerchantsFragment : Fragment(), OnMapReadyCallback, SearchView.OnSuggestio
// Force marker to use a custom info window
mTellerClusterManager?.markerCollection?.setOnInfoWindowAdapter(TellerInfoWindowAdapter())
mMerchantViewModel.getAllTellers().observe(this, Observer<List<Teller>> { tellers ->
viewModel.getAllTellers().observe(viewLifecycleOwner, { tellers ->
this.tellers.clear()
this.tellers.addAll(tellers)
showHideTellersMarkers()

View File

@ -11,8 +11,7 @@ import android.widget.AdapterView
import androidx.appcompat.widget.Toolbar
import androidx.collection.LongSparseArray
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.fragment.app.viewModels
import com.google.common.primitives.UnsignedLong
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.jakewharton.rxbinding3.widget.textChanges
@ -52,11 +51,11 @@ class ReceiveTransactionFragment : ConnectedFragment() {
private const val OTHER_ASSET = "other_asset"
}
private val viewModel: ReceiveTransactionViewModel by viewModels()
private var _binding: FragmentReceiveTransactionBinding? = null
private val binding get() = _binding!!
private lateinit var mViewModel: ReceiveTransactionViewModel
/** Current user account */
private var mUserAccount: UserAccount? = null
@ -118,53 +117,49 @@ class ReceiveTransactionFragment : ConnectedFragment() {
crashlytics.setCustomKey(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG)
// Configure ViewModel
mViewModel = ViewModelProviders.of(this).get(ReceiveTransactionViewModel::class.java)
val userId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "")
mViewModel.getUserAccount(userId!!).observe(this,
Observer<cy.agorise.bitsybitshareswallet.database.entities.UserAccount> { user ->
mUserAccount = UserAccount(user.id, user.name)
})
viewModel.getUserAccount(userId!!).observe(viewLifecycleOwner, { user ->
mUserAccount = UserAccount(user.id, user.name)
})
mViewModel.getAllNonZero().observe(this,
Observer<List<cy.agorise.bitsybitshareswallet.database.entities.Asset>> { assets ->
mAssets.clear()
mAssets.addAll(assets)
viewModel.getAllNonZero().observe(viewLifecycleOwner, { assets ->
mAssets.clear()
mAssets.addAll(assets)
// Add BTS to always show a QR
if (mAssets.isEmpty())
mAssets.add(
cy.agorise.bitsybitshareswallet.database.entities.Asset(
"1.3.0", "BTS", 5, "", ""
)
// Add BTS to always show a QR
if (mAssets.isEmpty())
mAssets.add(
cy.agorise.bitsybitshareswallet.database.entities.Asset(
"1.3.0", "BTS", 5, "", ""
)
mAssets.sortWith(
Comparator { a, b -> a.toString().compareTo(b.toString(), true) }
)
// Add an option at the end so the user can search for an asset other than the ones saved in the db
val asset = cy.agorise.bitsybitshareswallet.database.entities.Asset(
OTHER_ASSET, getString(R.string.text__other), 0, "", ""
)
mAssets.add(asset)
mAssets.sortWith(
Comparator { a, b -> a.toString().compareTo(b.toString(), true) }
)
mAssetsAdapter =
AssetsAdapter(context!!, android.R.layout.simple_spinner_item, mAssets)
binding.spAsset.adapter = mAssetsAdapter
// Add an option at the end so the user can search for an asset other than the ones saved in the db
val asset = cy.agorise.bitsybitshareswallet.database.entities.Asset(
OTHER_ASSET, getString(R.string.text__other), 0, "", ""
)
mAssets.add(asset)
// Try to select the selectedAssetSymbol
for (i in 0 until mAssetsAdapter!!.count) {
if (mAssetsAdapter!!.getItem(i)!!.symbol == selectedAssetSymbol) {
binding.spAsset.setSelection(i)
break
}
mAssetsAdapter =
AssetsAdapter(requireContext(), android.R.layout.simple_spinner_item, mAssets)
binding.spAsset.adapter = mAssetsAdapter
// Try to select the selectedAssetSymbol
for (i in 0 until mAssetsAdapter!!.count) {
if (mAssetsAdapter!!.getItem(i)!!.symbol == selectedAssetSymbol) {
binding.spAsset.setSelection(i)
break
}
})
}
})
mViewModel.qrCodeBitmap.observe(this, Observer { bitmap ->
viewModel.qrCodeBitmap.observe(viewLifecycleOwner, { bitmap ->
binding.ivQR.setImageBitmap(bitmap)
})
@ -204,7 +199,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
// Add adapter to the Assets AutoCompleteTextView
mAutoSuggestAssetAdapter =
AutoSuggestAssetAdapter(context!!, android.R.layout.simple_dropdown_item_1line)
AutoSuggestAssetAdapter(requireContext(), android.R.layout.simple_dropdown_item_1line)
binding.actvAsset.setAdapter(mAutoSuggestAssetAdapter)
// 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())
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)
} catch (e: NullPointerException) {
Log.e(TAG, "NullPointerException. Msg: " + e.message)
@ -366,7 +361,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
private fun verifyStoragePermission() {
if (ContextCompat.checkSelfPermission(
activity!!,
requireActivity(),
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
!= PackageManager.PERMISSION_GRANTED
@ -411,7 +406,7 @@ class ReceiveTransactionFragment : ConnectedFragment() {
// Get Screenshot
val screenshot = Helper.loadBitmapFromView(binding.container)
val imageUri = Helper.saveTemporalBitmap(context!!, screenshot)
val imageUri = Helper.saveTemporalBitmap(requireContext(), screenshot)
// Prepare information for share intent
val subject = getString(R.string.msg__invoice_subject, mUserAccount?.name)
@ -428,4 +423,4 @@ class ReceiveTransactionFragment : ConnectedFragment() {
shareIntent.type = "*/*"
startActivity(Intent.createChooser(shareIntent, getString(R.string.text__share_with)))
}
}
}

View File

@ -12,8 +12,7 @@ import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.collection.LongSparseArray
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.afollestad.materialdialogs.MaterialDialog
@ -74,13 +73,15 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
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 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 */
private var isCameraPreviewVisible = false
@ -90,8 +91,6 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
private var mBalancesDetails = ArrayList<BalanceDetail>()
private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel
private var mBalancesDetailsAdapter: BalancesDetailsAdapter? = null
/** Keeps track of the asset's symbol selected in the Asset spinner */
@ -162,10 +161,8 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
mUserAccount = UserAccount(userId)
// Configure ViewModel
mViewModel = ViewModelProviders.of(this).get(SendTransactionViewModel::class.java)
mViewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal).observe(this,
Observer<String> { encryptedWIF ->
viewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal)
.observe(viewLifecycleOwner, { encryptedWIF ->
context?.let {
try {
wifKey = CryptoUtils.decrypt(it, encryptedWIF)
@ -186,31 +183,27 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
binding.fabOpenCamera.setOnClickListener { if (isCameraPreviewVisible) stopCameraPreview() else verifyCameraPermission() }
// Configure BalanceDetailViewModel to show the current balances
mBalanceDetailViewModel =
ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java)
balanceDetailViewModel.getAll().observe(viewLifecycleOwner, { balancesDetails ->
mBalancesDetails.clear()
mBalancesDetails.addAll(balancesDetails)
mBalancesDetails.sortWith(
Comparator { a, b -> a.toString().compareTo(b.toString(), true) }
)
mBalancesDetailsAdapter = BalancesDetailsAdapter(
requireContext(),
android.R.layout.simple_spinner_item,
mBalancesDetails
)
binding.spAsset.adapter = mBalancesDetailsAdapter
mBalanceDetailViewModel.getAll()
.observe(this, Observer<List<BalanceDetail>> { balancesDetails ->
mBalancesDetails.clear()
mBalancesDetails.addAll(balancesDetails)
mBalancesDetails.sortWith(
Comparator { a, b -> a.toString().compareTo(b.toString(), true) }
)
mBalancesDetailsAdapter = BalancesDetailsAdapter(
context!!,
android.R.layout.simple_spinner_item,
mBalancesDetails
)
binding.spAsset.adapter = mBalancesDetailsAdapter
// Try to select the selectedAssetSymbol
for (i in 0 until mBalancesDetailsAdapter!!.count) {
if (mBalancesDetailsAdapter!!.getItem(i)!!.symbol == selectedAssetSymbol) {
binding.spAsset.setSelection(i)
break
}
// Try to select the selectedAssetSymbol
for (i in 0 until mBalancesDetailsAdapter!!.count) {
if (mBalancesDetailsAdapter!!.getItem(i)!!.symbol == selectedAssetSymbol) {
binding.spAsset.setSelection(i)
break
}
})
}
})
binding.spAsset.onItemSelectedListener = assetItemSelectedListener
@ -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 */
private fun verifyCameraPermission() {
if (ContextCompat.checkSelfPermission(activity!!, android.Manifest.permission.CAMERA)
if (ContextCompat.checkSelfPermission(requireActivity(), android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED
) {
// Permission is not already granted
@ -711,7 +704,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_info) {
MaterialDialog(context!!).show {
MaterialDialog(requireContext()).show {
customView(R.layout.dialog_send_transaction_info, scrollable = true)
positiveButton(android.R.string.ok) { dismiss() }
}

View File

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

View File

@ -11,8 +11,7 @@ import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsMultiChoice
@ -20,7 +19,6 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.jakewharton.rxbinding3.appcompat.queryTextChangeEvents
import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.adapters.TransfersDetailsAdapter
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
import cy.agorise.bitsybitshareswallet.databinding.FragmentTransactionsBinding
import cy.agorise.bitsybitshareswallet.models.FilterOptions
import cy.agorise.bitsybitshareswallet.utils.*
@ -42,11 +40,11 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100
}
private val viewModel: TransactionsViewModel by viewModels()
private var _binding: FragmentTransactionsBinding? = null
private val binding get() = _binding!!
private lateinit var mViewModel: TransactionsViewModel
private var mDisposables = CompositeDisposable()
override fun onCreateView(
@ -74,31 +72,28 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
val userId = PreferenceManager.getDefaultSharedPreferences(context)
.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
val transfersDetailsAdapter = TransfersDetailsAdapter(context!!)
val transfersDetailsAdapter = TransfersDetailsAdapter(requireContext())
binding.rvTransactions.adapter = transfersDetailsAdapter
binding.rvTransactions.layoutManager = LinearLayoutManager(context)
// Configure TransactionsViewModel to fetch the transaction history
mViewModel = ViewModelProviders.of(this).get(TransactionsViewModel::class.java)
viewModel.getFilteredTransactions(userId).observe(viewLifecycleOwner, { transactions ->
if (transactions.isEmpty()) {
binding.rvTransactions.visibility = View.GONE
binding.tvEmpty.visibility = View.VISIBLE
} else {
binding.rvTransactions.visibility = View.VISIBLE
binding.tvEmpty.visibility = View.GONE
mViewModel.getFilteredTransactions(userId).observe(this,
Observer<List<TransferDetail>> { transactions ->
if (transactions.isEmpty()) {
binding.rvTransactions.visibility = View.GONE
binding.tvEmpty.visibility = View.VISIBLE
} else {
binding.rvTransactions.visibility = View.VISIBLE
binding.tvEmpty.visibility = View.GONE
val shouldScrollUp = transactions.size - transfersDetailsAdapter.itemCount == 1
transfersDetailsAdapter.replaceAll(transactions)
val shouldScrollUp = transactions.size - transfersDetailsAdapter.itemCount == 1
transfersDetailsAdapter.replaceAll(transactions)
// Scroll to the top only if the difference between old and new items is 1
// which most likely means a new transaction was received/sent.
if (shouldScrollUp)
binding.rvTransactions.scrollToPosition(0)
}
})
// Scroll to the top only if the difference between old and new items is 1
// which most likely means a new transaction was received/sent.
if (shouldScrollUp)
binding.rvTransactions.scrollToPosition(0)
}
})
// Set custom touch listener to handle bounce/stretch effect
val bounceTouchListener = BounceTouchListener(binding.rvTransactions)
@ -118,7 +113,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
.map { it.queryText.toString().toLowerCase() }
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
mViewModel.setFilterQuery(it)
viewModel.setFilterQuery(it)
}
)
@ -133,7 +128,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
val args = Bundle()
args.putParcelable(
FilterOptionsDialog.KEY_FILTER_OPTIONS,
mViewModel.getFilterOptions()
viewModel.getFilterOptions()
)
filterOptionsDialog.arguments = args
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.
*/
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 */
private fun verifyStoragePermission() {
if (ContextCompat.checkSelfPermission(
activity!!,
requireActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
!= PackageManager.PERMISSION_GRANTED
@ -205,7 +200,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
}
private fun showExportOptionsDialog() {
MaterialDialog(context!!).show {
MaterialDialog(requireContext()).show {
title(R.string.title_export_transactions)
listItemsMultiChoice(
R.array.export_options,
@ -228,7 +223,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
return
}
mViewModel.getFilteredTransactionsOnce()?.let { filteredTransactions ->
viewModel.getFilteredTransactionsOnce()?.let { filteredTransactions ->
if (exportPDF)
activity?.let { PDFGeneratorTask(it).execute(filteredTransactions) }

View File

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