Avoid requesting storage permission to share eReceipt.

This commit is contained in:
Severiano Jaramillo 2022-05-27 22:38:06 -07:00
parent ac06a3d708
commit 23f4170628
3 changed files with 64 additions and 101 deletions

View file

@ -16,7 +16,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SortedList import androidx.recyclerview.widget.SortedList
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
import cy.agorise.bitsybitshareswallet.fragments.TransactionsFragmentDirections import cy.agorise.bitsybitshareswallet.ui.transactions.TransactionsFragmentDirections
import java.math.RoundingMode import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols

View file

@ -1,8 +1,6 @@
package cy.agorise.bitsybitshareswallet.fragments package cy.agorise.bitsybitshareswallet.fragments
import android.Manifest
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.drawable.Animatable import android.graphics.drawable.Animatable
import android.os.Bundle import android.os.Bundle
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
@ -20,7 +18,6 @@ import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
import cy.agorise.bitsybitshareswallet.databinding.FragmentEReceiptBinding import cy.agorise.bitsybitshareswallet.databinding.FragmentEReceiptBinding
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.utils.Helper import cy.agorise.bitsybitshareswallet.utils.Helper
import cy.agorise.bitsybitshareswallet.utils.toast
import cy.agorise.bitsybitshareswallet.viewmodels.EReceiptViewModel import cy.agorise.bitsybitshareswallet.viewmodels.EReceiptViewModel
import java.math.RoundingMode import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
@ -28,15 +25,10 @@ import java.text.DecimalFormatSymbols
import java.text.NumberFormat import java.text.NumberFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import kotlin.math.pow
class EReceiptFragment : Fragment() { class EReceiptFragment : Fragment() {
companion object {
private const val TAG = "EReceiptFragment"
private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100
}
private val args: EReceiptFragmentArgs by navArgs() private val args: EReceiptFragmentArgs by navArgs()
private val viewModel: EReceiptViewModel by viewModels() private val viewModel: EReceiptViewModel by viewModels()
@ -75,9 +67,9 @@ class EReceiptFragment : Fragment() {
val transferId = args.transferId val transferId = args.transferId
viewModel.get(userId, transferId).observe(viewLifecycleOwner, { transferDetail -> viewModel.get(userId, transferId).observe(viewLifecycleOwner) { transferDetail ->
bindTransferDetail(transferDetail) bindTransferDetail(transferDetail)
}) }
} }
private fun bindTransferDetail(transferDetail: TransferDetail) { private fun bindTransferDetail(transferDetail: TransferDetail) {
@ -95,7 +87,7 @@ class EReceiptFragment : Fragment() {
df.decimalFormatSymbols = DecimalFormatSymbols(Locale.getDefault()) df.decimalFormatSymbols = DecimalFormatSymbols(Locale.getDefault())
val amount = transferDetail.assetAmount.toDouble() / val amount = transferDetail.assetAmount.toDouble() /
Math.pow(10.toDouble(), transferDetail.assetPrecision.toDouble()) 10.toDouble().pow(transferDetail.assetPrecision.toDouble())
val assetAmount = "${df.format(amount)} ${transferDetail.getUIAssetSymbol()}" val assetAmount = "${df.format(amount)} ${transferDetail.getUIAssetSymbol()}"
binding.tvAmount.text = assetAmount binding.tvAmount.text = assetAmount
@ -104,7 +96,7 @@ class EReceiptFragment : Fragment() {
val numberFormat = NumberFormat.getNumberInstance() val numberFormat = NumberFormat.getNumberInstance()
val currency = Currency.getInstance(transferDetail.fiatSymbol) val currency = Currency.getInstance(transferDetail.fiatSymbol)
val fiatEquivalent = transferDetail.fiatAmount.toDouble() / val fiatEquivalent = transferDetail.fiatAmount.toDouble() /
Math.pow(10.0, currency.defaultFractionDigits.toDouble()) 10.0.pow(currency.defaultFractionDigits.toDouble())
val equivalentValue = "${numberFormat.format(fiatEquivalent)} ${currency.currencyCode}" val equivalentValue = "${numberFormat.format(fiatEquivalent)} ${currency.currencyCode}"
binding.tvEquivalentValue.text = equivalentValue binding.tvEquivalentValue.text = equivalentValue
@ -151,47 +143,13 @@ class EReceiptFragment : Fragment() {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_share) { if (item.itemId == R.id.menu_share) {
verifyStoragePermission() shareEReceiptScreenshot()
return true return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
/** Verifies if the storage permission is already granted, if that is the case then it takes the screenshot and
* shares it but if it is not then it asks the user for that permission */
private fun verifyStoragePermission() {
if (ContextCompat
.checkSelfPermission(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
) {
// Permission is not already granted
requestPermissions(
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION
)
} else {
// Permission is already granted
shareEReceiptScreenshot()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
shareEReceiptScreenshot()
} else {
context?.toast(getString(R.string.msg__storage_permission_necessary_share))
}
return
}
}
/** Takes a screenshot as a bitmap (hiding the tx hyperlink), saves it into a temporal cache image and then /** Takes a screenshot as a bitmap (hiding the tx hyperlink), saves it into a temporal cache image and then
* sends an intent so the user can select the desired method to share the image. */ * sends an intent so the user can select the desired method to share the image. */
private fun shareEReceiptScreenshot() { private fun shareEReceiptScreenshot() {
@ -214,4 +172,8 @@ class EReceiptFragment : Fragment() {
shareIntent.type = "*/*" shareIntent.type = "*/*"
startActivity(Intent.createChooser(shareIntent, getString(R.string.text__share_with))) startActivity(Intent.createChooser(shareIntent, getString(R.string.text__share_with)))
} }
companion object {
private const val TAG = "EReceiptFragment"
}
} }

View file

@ -81,8 +81,6 @@ class TransactionsViewModel(application: Application) : AndroidViewModel(applica
} }
} }
internal fun getFilteredTransactionsOnce() = filteredTransactions.value
/** /**
* Filters the given list of [TransferDetail] given the [FilterOptions] and returns a filtered list * Filters the given list of [TransferDetail] given the [FilterOptions] and returns a filtered list
* of [TransferDetail], doing all the work in a background thread using kotlin coroutines * of [TransferDetail], doing all the work in a background thread using kotlin coroutines
@ -90,58 +88,56 @@ class TransactionsViewModel(application: Application) : AndroidViewModel(applica
private suspend fun filter( private suspend fun filter(
transactions: List<TransferDetail>, transactions: List<TransferDetail>,
filterOptions: FilterOptions filterOptions: FilterOptions
): List<TransferDetail> { ): List<TransferDetail> = withContext(Dispatchers.Default) {
return withContext(Dispatchers.Default) {
// Create a list to store the filtered transactions // Create a list to store the filtered transactions
val filteredTransactions = ArrayList<TransferDetail>() val filteredTransactions = ArrayList<TransferDetail>()
// Make sure the filter dates use the same format as the transactions' dates // Make sure the filter dates use the same format as the transactions' dates
val startDate = filterOptions.startDate / 1000 val startDate = filterOptions.startDate / 1000
val endDate = filterOptions.endDate / 1000 val endDate = filterOptions.endDate / 1000
for (transaction in transactions) { for (transaction in transactions) {
// Filter by transfer direction // Filter by transfer direction
if (transaction.direction) { // Transfer sent if (transaction.direction) { // Transfer sent
if (filterOptions.transactionsDirection == 1) if (filterOptions.transactionsDirection == 1)
// Looking for received transfers only // Looking for received transfers only
continue
} else { // Transfer received
if (filterOptions.transactionsDirection == 2)
// Looking for sent transactions only
continue
}
// Filter by date range
if (!filterOptions.dateRangeAll && (transaction.date < startDate ||
transaction.date > endDate)
)
continue continue
} else { // Transfer received
// Filter by asset if (filterOptions.transactionsDirection == 2)
if (!filterOptions.assetAll && transaction.assetSymbol != filterOptions.asset) // Looking for sent transactions only
continue continue
// Filter by equivalent value
if (!filterOptions.equivalentValueAll && ((transaction.fiatAmount
?: -1) < filterOptions.fromEquivalentValue
|| (transaction.fiatAmount ?: -1) > filterOptions.toEquivalentValue)
)
continue
// Filter transactions sent to agorise
if (filterOptions.agoriseFees && transaction.to.equals("agorise"))
continue
// Filter by search query
val text = "${transaction.from ?: ""} ${transaction.to ?: ""} ${transaction.memo}"
if (text.contains(filterOptions.query, ignoreCase = true)) {
filteredTransactions.add(transaction)
}
} }
filteredTransactions // Filter by date range
if (!filterOptions.dateRangeAll && (transaction.date < startDate ||
transaction.date > endDate)
)
continue
// Filter by asset
if (!filterOptions.assetAll && transaction.assetSymbol != filterOptions.asset)
continue
// Filter by equivalent value
if (!filterOptions.equivalentValueAll && ((transaction.fiatAmount
?: -1) < filterOptions.fromEquivalentValue
|| (transaction.fiatAmount ?: -1) > filterOptions.toEquivalentValue)
)
continue
// Filter transactions sent to agorise
if (filterOptions.agoriseFees && transaction.to.equals("agorise"))
continue
// Filter by search query
val text = "${transaction.from ?: ""} ${transaction.to ?: ""} ${transaction.memo}"
if (text.contains(filterOptions.query, ignoreCase = true)) {
filteredTransactions.add(transaction)
}
} }
filteredTransactions
} }
/** Creates the export procedures for PDF and CSV, depending on the user selection. */ /** Creates the export procedures for PDF and CSV, depending on the user selection. */
@ -152,13 +148,18 @@ class TransactionsViewModel(application: Application) : AndroidViewModel(applica
// TODO Use injected context // TODO Use injected context
val folderDocumentFile = DocumentFile.fromTreeUri(getApplication(), folderUri) ?: return val folderDocumentFile = DocumentFile.fromTreeUri(getApplication(), folderUri) ?: return
val transactions = filteredTransactions.value ?: return
if (exportPdf) { if (exportPdf) {
viewModelScope.launch { viewModelScope.launch {
filteredTransactions.value?.let { transactions -> // TODO Show success/failure message
// TODO Show success/failure message exportTransactionsToPdfUseCase(transactions, folderDocumentFile)
exportTransactionsToPdfUseCase(transactions, folderDocumentFile) }
} }
if (exportCsv) {
viewModelScope.launch {
// TODO Export CSV
} }
} }
} }