Created FilterOptions class to serve as an easy way to communicate filter options user preferences between the TransactionsFragment and the FilterOptionsDialog, and use it to filter the transactions list.

This commit is contained in:
Severiano Jaramillo 2019-04-26 14:41:34 -05:00
parent 4ed2eba66a
commit d1bce06ec2
4 changed files with 135 additions and 137 deletions

View file

@ -18,6 +18,7 @@ import com.crashlytics.android.Crashlytics
import cy.agorise.bitsybitshareswallet.R import cy.agorise.bitsybitshareswallet.R
import cy.agorise.bitsybitshareswallet.adapters.BalancesDetailsAdapter import cy.agorise.bitsybitshareswallet.adapters.BalancesDetailsAdapter
import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail import cy.agorise.bitsybitshareswallet.database.joins.BalanceDetail
import cy.agorise.bitsybitshareswallet.models.FilterOptions
import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.utils.Constants
import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel import cy.agorise.bitsybitshareswallet.viewmodels.BalanceDetailViewModel
import cy.agorise.bitsybitshareswallet.views.DatePickerFragment import cy.agorise.bitsybitshareswallet.views.DatePickerFragment
@ -36,44 +37,16 @@ class FilterOptionsDialog : DialogFragment() {
companion object { companion object {
private const val TAG = "FilterOptionsDialog" private const val TAG = "FilterOptionsDialog"
const val KEY_FILTER_TRANSACTION_DIRECTION = "key_filter_transaction_direction" const val KEY_FILTER_OPTIONS = "key_filter_options"
const val KEY_FILTER_DATE_RANGE_ALL = "key_filter_date_range_all"
const val KEY_FILTER_START_DATE = "key_filter_start_date"
const val KEY_FILTER_END_DATE = "key_filter_end_date"
const val KEY_FILTER_ASSET_ALL = "key_filter_asset_all"
const val KEY_FILTER_ASSET = "key_filter_asset"
const val KEY_FILTER_EQUIVALENT_VALUE_ALL = "key_filter_equivalent_value_all"
const val KEY_FILTER_FROM_EQUIVALENT_VALUE = "key_filter_from_equivalent_value"
const val KEY_FILTER_TO_EQUIVALENT_VALUE = "key_filter_to_equivalent_value"
const val KEY_FILTER_AGORISE_FEES = "key_filter_agorise_fees"
const val KEY_TIMESTAMP = "key_timestamp" const val KEY_TIMESTAMP = "key_timestamp"
const val START_DATE_PICKER = 0 const val START_DATE_PICKER = 0
const val END_DATE_PICKER = 1 const val END_DATE_PICKER = 1
fun newInstance(filterTransactionsDirection: Int, filterDateRangeAll: Boolean,
filterStartDate: Long, filterEndDate: Long, filterAssetAll: Boolean,
filterAsset: String, filterEquivalentValueAll: Boolean, filterFromEquivalentValue: Long,
filterToEquivalentValue: Long, filterAgoriseFees: Boolean): FilterOptionsDialog {
val frag = FilterOptionsDialog()
val args = Bundle()
args.putInt(KEY_FILTER_TRANSACTION_DIRECTION, filterTransactionsDirection)
args.putBoolean(KEY_FILTER_DATE_RANGE_ALL, filterDateRangeAll)
args.putLong(KEY_FILTER_START_DATE, filterStartDate)
args.putLong(KEY_FILTER_END_DATE, filterEndDate)
args.putBoolean(KEY_FILTER_ASSET_ALL, filterAssetAll)
args.putString(KEY_FILTER_ASSET, filterAsset)
args.putBoolean(KEY_FILTER_EQUIVALENT_VALUE_ALL, filterEquivalentValueAll)
args.putLong(KEY_FILTER_FROM_EQUIVALENT_VALUE, filterFromEquivalentValue)
args.putLong(KEY_FILTER_TO_EQUIVALENT_VALUE, filterToEquivalentValue)
args.putBoolean(KEY_FILTER_AGORISE_FEES, filterAgoriseFees)
frag.arguments = args
return frag
}
} }
private lateinit var mFilterOptions: FilterOptions
// Widgets TODO use android-kotlin-extensions {onViewCreated} // Widgets TODO use android-kotlin-extensions {onViewCreated}
private lateinit var rbTransactionAll: RadioButton private lateinit var rbTransactionAll: RadioButton
private lateinit var rbTransactionSent: RadioButton private lateinit var rbTransactionSent: RadioButton
@ -98,9 +71,6 @@ class FilterOptionsDialog : DialogFragment() {
private var dateFormat: SimpleDateFormat = SimpleDateFormat("d/MMM/yyyy", private var dateFormat: SimpleDateFormat = SimpleDateFormat("d/MMM/yyyy",
ConfigurationCompat.getLocales(Resources.getSystem().configuration)[0]) ConfigurationCompat.getLocales(Resources.getSystem().configuration)[0])
private var startDate: Long = 0
private var endDate: Long = 0
private var mBalanceDetails = ArrayList<BalanceDetail>() private var mBalanceDetails = ArrayList<BalanceDetail>()
private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel private lateinit var mBalanceDetailViewModel: BalanceDetailViewModel
@ -121,22 +91,22 @@ class FilterOptionsDialog : DialogFragment() {
//Log.d(TAG, "timestamp: $timestamp") //Log.d(TAG, "timestamp: $timestamp")
when (msg.arg1) { when (msg.arg1) {
START_DATE_PICKER -> { START_DATE_PICKER -> {
startDate = timestamp mFilterOptions.startDate = timestamp
updateDateTextViews() updateDateTextViews()
} }
END_DATE_PICKER -> { END_DATE_PICKER -> {
endDate = timestamp mFilterOptions.endDate = timestamp
// Make sure there is at least one moth difference between start and end time // Make sure there is at least one moth difference between start and end time
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.timeInMillis = endDate calendar.timeInMillis = mFilterOptions.endDate
calendar.add(Calendar.MONTH, -1) calendar.add(Calendar.MONTH, -1)
val tmpTime = calendar.timeInMillis val tmpTime = calendar.timeInMillis
if (tmpTime < startDate) if (tmpTime < mFilterOptions.startDate)
startDate = tmpTime mFilterOptions.startDate = tmpTime
updateDateTextViews() updateDateTextViews()
} }
@ -145,25 +115,16 @@ class FilterOptionsDialog : DialogFragment() {
} }
private fun updateDateTextViews() { private fun updateDateTextViews() {
var date = Date(startDate) var date = Date(mFilterOptions.startDate)
tvStartDate.text = dateFormat.format(date) tvStartDate.text = dateFormat.format(date)
date = Date(endDate) date = Date(mFilterOptions.endDate)
tvEndDate.text = dateFormat.format(date) tvEndDate.text = dateFormat.format(date)
} }
// Container Fragment must implement this interface // Container Fragment must implement this interface
interface OnFilterOptionsSelectedListener { interface OnFilterOptionsSelectedListener {
fun onFilterOptionsSelected(filterTransactionsDirection: Int, fun onFilterOptionsSelected(filterOptions: FilterOptions)
filterDateRangeAll: Boolean,
filterStartDate: Long,
filterEndDate: Long,
filterAssetAll: Boolean,
filterAsset: String,
filterEquivalentValueAll: Boolean,
filterFromEquivalentValue: Long,
filterToEquivalentValue: Long,
filterAgoriseFees: Boolean)
} }
@ -172,6 +133,8 @@ class FilterOptionsDialog : DialogFragment() {
Crashlytics.setString(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG) Crashlytics.setString(Constants.CRASHLYTICS_KEY_LAST_SCREEN, TAG)
mFilterOptions = arguments?.getParcelable(KEY_FILTER_OPTIONS)!!
// Initialize handler for communication with the DatePicker // Initialize handler for communication with the DatePicker
mDatePickerHandler = DatePickerHandler() mDatePickerHandler = DatePickerHandler()
@ -188,8 +151,7 @@ class FilterOptionsDialog : DialogFragment() {
rbTransactionAll = view.findViewById(R.id.rbTransactionAll) rbTransactionAll = view.findViewById(R.id.rbTransactionAll)
rbTransactionSent = view.findViewById(R.id.rbTransactionSent) rbTransactionSent = view.findViewById(R.id.rbTransactionSent)
rbTransactionReceived = view.findViewById(R.id.rbTransactionReceived) rbTransactionReceived = view.findViewById(R.id.rbTransactionReceived)
val radioButtonChecked = arguments!!.getInt(KEY_FILTER_TRANSACTION_DIRECTION, 0) when (mFilterOptions.transactionsDirection) {
when (radioButtonChecked) {
0 -> rbTransactionAll.isChecked = true 0 -> rbTransactionAll.isChecked = true
1 -> rbTransactionSent.isChecked = true 1 -> rbTransactionSent.isChecked = true
2 -> rbTransactionReceived.isChecked = true 2 -> rbTransactionReceived.isChecked = true
@ -200,15 +162,13 @@ class FilterOptionsDialog : DialogFragment() {
llDateRange = view.findViewById(R.id.llDateRange) llDateRange = view.findViewById(R.id.llDateRange)
cbDateRange.setOnCheckedChangeListener { _, isChecked -> cbDateRange.setOnCheckedChangeListener { _, isChecked ->
llDateRange.visibility = if(isChecked) View.GONE else View.VISIBLE } llDateRange.visibility = if(isChecked) View.GONE else View.VISIBLE }
cbDateRange.isChecked = arguments!!.getBoolean(KEY_FILTER_DATE_RANGE_ALL, true) cbDateRange.isChecked = mFilterOptions.dateRangeAll
tvStartDate = view.findViewById(R.id.tvStartDate) tvStartDate = view.findViewById(R.id.tvStartDate)
tvEndDate = view.findViewById(R.id.tvEndDate) tvEndDate = view.findViewById(R.id.tvEndDate)
startDate = arguments!!.getLong(KEY_FILTER_START_DATE, 0)
tvStartDate.setOnClickListener(mDateClickListener) tvStartDate.setOnClickListener(mDateClickListener)
endDate = arguments!!.getLong(KEY_FILTER_END_DATE, 0)
tvEndDate.setOnClickListener(mDateClickListener) tvEndDate.setOnClickListener(mDateClickListener)
updateDateTextViews() updateDateTextViews()
@ -219,7 +179,7 @@ class FilterOptionsDialog : DialogFragment() {
cbAsset.setOnCheckedChangeListener { _, isChecked -> cbAsset.setOnCheckedChangeListener { _, isChecked ->
sAsset.visibility = if(isChecked) View.GONE else View.VISIBLE sAsset.visibility = if(isChecked) View.GONE else View.VISIBLE
} }
cbAsset.isChecked = arguments!!.getBoolean(KEY_FILTER_ASSET_ALL, true) cbAsset.isChecked = mFilterOptions.assetAll
// Configure BalanceDetailViewModel to obtain the user's Balances // Configure BalanceDetailViewModel to obtain the user's Balances
mBalanceDetailViewModel = ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java) mBalanceDetailViewModel = ViewModelProviders.of(this).get(BalanceDetailViewModel::class.java)
@ -233,11 +193,9 @@ class FilterOptionsDialog : DialogFragment() {
mBalancesDetailsAdapter = BalancesDetailsAdapter(context!!, android.R.layout.simple_spinner_item, mBalanceDetails) mBalancesDetailsAdapter = BalancesDetailsAdapter(context!!, android.R.layout.simple_spinner_item, mBalanceDetails)
sAsset.adapter = mBalancesDetailsAdapter sAsset.adapter = mBalancesDetailsAdapter
val assetSelected = arguments!!.getString(KEY_FILTER_ASSET)
// Try to select the selectedAssetSymbol // Try to select the selectedAssetSymbol
for (i in 0 until mBalancesDetailsAdapter!!.count) { for (i in 0 until mBalancesDetailsAdapter!!.count) {
if (mBalancesDetailsAdapter!!.getItem(i)!!.symbol == assetSelected) { if (mBalancesDetailsAdapter!!.getItem(i)!!.symbol == mFilterOptions.asset) {
sAsset.setSelection(i) sAsset.setSelection(i)
break break
} }
@ -249,19 +207,19 @@ class FilterOptionsDialog : DialogFragment() {
llEquivalentValue = view.findViewById(R.id.llEquivalentValue) llEquivalentValue = view.findViewById(R.id.llEquivalentValue)
cbEquivalentValue.setOnCheckedChangeListener { _, isChecked -> cbEquivalentValue.setOnCheckedChangeListener { _, isChecked ->
llEquivalentValue.visibility = if(isChecked) View.GONE else View.VISIBLE } llEquivalentValue.visibility = if(isChecked) View.GONE else View.VISIBLE }
cbEquivalentValue.isChecked = arguments!!.getBoolean(KEY_FILTER_EQUIVALENT_VALUE_ALL, true) cbEquivalentValue.isChecked = mFilterOptions.equivalentValueAll
// TODO obtain user selected currency // TODO obtain user selected currency
val currencySymbol = "usd" val currencySymbol = "usd"
mCurrency = Currency.getInstance(currencySymbol) mCurrency = Currency.getInstance(currencySymbol)
etFromEquivalentValue = view.findViewById(R.id.etFromEquivalentValue) etFromEquivalentValue = view.findViewById(R.id.etFromEquivalentValue)
val fromEquivalentValue = arguments!!.getLong(KEY_FILTER_FROM_EQUIVALENT_VALUE, 0) / val fromEquivalentValue = mFilterOptions.fromEquivalentValue /
Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong() Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong()
etFromEquivalentValue.setText("$fromEquivalentValue", TextView.BufferType.EDITABLE) etFromEquivalentValue.setText("$fromEquivalentValue", TextView.BufferType.EDITABLE)
etToEquivalentValue = view.findViewById(R.id.etToEquivalentValue) etToEquivalentValue = view.findViewById(R.id.etToEquivalentValue)
val toEquivalentValue = arguments!!.getLong(KEY_FILTER_TO_EQUIVALENT_VALUE, 0) / val toEquivalentValue = mFilterOptions.toEquivalentValue /
Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong() Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong()
etToEquivalentValue.setText("$toEquivalentValue", TextView.BufferType.EDITABLE) etToEquivalentValue.setText("$toEquivalentValue", TextView.BufferType.EDITABLE)
@ -270,7 +228,7 @@ class FilterOptionsDialog : DialogFragment() {
// Initialize transaction network fees // Initialize transaction network fees
switchAgoriseFees = view.findViewById(R.id.switchAgoriseFees) switchAgoriseFees = view.findViewById(R.id.switchAgoriseFees)
switchAgoriseFees.isChecked = arguments!!.getBoolean(KEY_FILTER_AGORISE_FEES, true) switchAgoriseFees.isChecked = mFilterOptions.agoriseFees
builder.setView(view) builder.setView(view)
@ -299,13 +257,13 @@ class FilterOptionsDialog : DialogFragment() {
var which = -1 var which = -1
if (v.id == R.id.tvStartDate) { if (v.id == R.id.tvStartDate) {
which = START_DATE_PICKER which = START_DATE_PICKER
currentTime = startDate currentTime = mFilterOptions.startDate
calendar.timeInMillis = endDate calendar.timeInMillis = mFilterOptions.endDate
calendar.add(Calendar.MONTH, -1) calendar.add(Calendar.MONTH, -1)
maxTime = calendar.timeInMillis maxTime = calendar.timeInMillis
} else if (v.id == R.id.tvEndDate) { } else if (v.id == R.id.tvEndDate) {
which = END_DATE_PICKER which = END_DATE_PICKER
currentTime = endDate currentTime = mFilterOptions.endDate
} }
val datePickerFragment = DatePickerFragment.newInstance(which, currentTime, val datePickerFragment = DatePickerFragment.newInstance(which, currentTime,
@ -314,36 +272,33 @@ class FilterOptionsDialog : DialogFragment() {
} }
private fun validateFields() { private fun validateFields() {
val filterTransactionsDirection = when { mFilterOptions.transactionsDirection = when {
rbTransactionAll.isChecked -> 0 rbTransactionAll.isChecked -> 0
rbTransactionSent.isChecked -> 1 rbTransactionSent.isChecked -> 1
rbTransactionReceived.isChecked -> 2 rbTransactionReceived.isChecked -> 2
else -> { 0 } else -> { 0 }
} }
val filterDateRangeAll = cbDateRange.isChecked mFilterOptions.dateRangeAll = cbDateRange.isChecked
val filterAssetAll = cbAsset.isChecked mFilterOptions.assetAll = cbAsset.isChecked
val filterAsset = (sAsset.selectedItem as BalanceDetail).symbol mFilterOptions.asset = (sAsset.selectedItem as BalanceDetail).symbol
val filterEquivalentValueAll = cbEquivalentValue.isChecked mFilterOptions.equivalentValueAll = cbEquivalentValue.isChecked
val filterFromEquivalentValue = etFromEquivalentValue.text.toString().toLong() * mFilterOptions.fromEquivalentValue = etFromEquivalentValue.text.toString().toLong() *
Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong() Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong()
var filterToEquivalentValue = etToEquivalentValue.text.toString().toLong() * mFilterOptions.toEquivalentValue = etToEquivalentValue.text.toString().toLong() *
Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong() Math.pow(10.0, mCurrency.defaultFractionDigits.toDouble()).toLong()
// Make sure ToEquivalentValue is at least 50 units bigger than FromEquivalentValue // Make sure ToEquivalentValue is at least 50 units bigger than FromEquivalentValue
if (!filterEquivalentValueAll && filterToEquivalentValue < filterFromEquivalentValue + 50) { mFilterOptions.toEquivalentValue =
filterToEquivalentValue = filterFromEquivalentValue + 50 Math.max(mFilterOptions.toEquivalentValue, mFilterOptions.fromEquivalentValue + 50)
}
val filterAgoriseFees = switchAgoriseFees.isChecked mFilterOptions.agoriseFees = switchAgoriseFees.isChecked
mCallback!!.onFilterOptionsSelected(filterTransactionsDirection, filterDateRangeAll, mCallback!!.onFilterOptionsSelected(mFilterOptions)
startDate, endDate, filterAssetAll, filterAsset, filterEquivalentValueAll,
filterFromEquivalentValue, filterToEquivalentValue, filterAgoriseFees)
} }
} }

View file

@ -21,8 +21,9 @@ 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.database.joins.TransferDetail
import cy.agorise.bitsybitshareswallet.models.FilterOptions
import cy.agorise.bitsybitshareswallet.utils.* import cy.agorise.bitsybitshareswallet.utils.*
import cy.agorise.bitsybitshareswallet.viewmodels.TransferDetailViewModel import cy.agorise.bitsybitshareswallet.viewmodels.TransactionsViewModel
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_transactions.* import kotlinx.android.synthetic.main.fragment_transactions.*
@ -31,6 +32,10 @@ import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
/**
* Shows the list of transactions as well as options to filter and export those transactions
* to PDF and CSV files
*/
class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSelectedListener { class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSelectedListener {
companion object { companion object {
@ -39,7 +44,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100 private const val REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION = 100
} }
private lateinit var mTransferDetailViewModel: TransferDetailViewModel private lateinit var mTransactionsViewModel: TransactionsViewModel
private lateinit var transfersDetailsAdapter: TransfersDetailsAdapter private lateinit var transfersDetailsAdapter: TransfersDetailsAdapter
@ -47,17 +52,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
private val filteredTransfersDetails = ArrayList<TransferDetail>() private val filteredTransfersDetails = ArrayList<TransferDetail>()
/** Variables used to filter the transaction items */ /** Variables used to filter the transaction items */
private var filterQuery = "" private var mFilterOptions = FilterOptions()
private var filterTransactionsDirection = 0
private var filterDateRangeAll = true
private var filterStartDate = 0L
private var filterEndDate = 0L
private var filterAssetAll = true
private var filterAsset = "BTS"
private var filterEquivalentValueAll = true
private var filterFromEquivalentValue = 0L
private var filterToEquivalentValue = 5000L
private var filterAgoriseFees = true
private var mDisposables = CompositeDisposable() private var mDisposables = CompositeDisposable()
@ -79,10 +74,10 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
rvTransactions.adapter = transfersDetailsAdapter rvTransactions.adapter = transfersDetailsAdapter
rvTransactions.layoutManager = LinearLayoutManager(context) rvTransactions.layoutManager = LinearLayoutManager(context)
// Configure TransferDetailViewModel to fetch the transaction history // Configure TransactionsViewModel to fetch the transaction history
mTransferDetailViewModel = ViewModelProviders.of(this).get(TransferDetailViewModel::class.java) mTransactionsViewModel = ViewModelProviders.of(this).get(TransactionsViewModel::class.java)
mTransferDetailViewModel.getAll(userId).observe(this, Observer<List<TransferDetail>> { transfersDetails -> mTransactionsViewModel.getAll(userId).observe(this, Observer<List<TransferDetail>> { transfersDetails ->
this.transfersDetails.clear() this.transfersDetails.clear()
this.transfersDetails.addAll(transfersDetails) this.transfersDetails.addAll(transfersDetails)
applyFilterOptions(false) applyFilterOptions(false)
@ -102,9 +97,9 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
// Initialize filter options // Initialize filter options
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
filterEndDate = calendar.timeInMillis / 1000 mFilterOptions.endDate = calendar.timeInMillis
calendar.add(Calendar.MONTH, -2) calendar.add(Calendar.MONTH, -2)
filterStartDate = calendar.timeInMillis / 1000 mFilterOptions.startDate = calendar.timeInMillis
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -120,7 +115,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
.map { it.queryText.toString().toLowerCase() } .map { it.queryText.toString().toLowerCase() }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
filterQuery = it mFilterOptions.query = it
applyFilterOptions() applyFilterOptions()
} }
) )
@ -132,11 +127,10 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.menu_filter -> { R.id.menu_filter -> {
val filterOptionsDialog = FilterOptionsDialog.newInstance( val filterOptionsDialog = FilterOptionsDialog()
filterTransactionsDirection, filterDateRangeAll, filterStartDate * 1000, val args = Bundle()
filterEndDate * 1000, filterAssetAll, filterAsset, args.putParcelable(FilterOptionsDialog.KEY_FILTER_OPTIONS, mFilterOptions)
filterEquivalentValueAll, filterFromEquivalentValue, filterToEquivalentValue, filterAgoriseFees filterOptionsDialog.arguments = args
)
filterOptionsDialog.show(childFragmentManager, "filter-options-tag") filterOptionsDialog.show(childFragmentManager, "filter-options-tag")
true true
} }
@ -168,38 +162,43 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
// Clean the filtered list // Clean the filtered list
filteredTransfersDetails.clear() filteredTransfersDetails.clear()
// Make sure the filter dates use the same format as the transactions' dates
val startDate = mFilterOptions.startDate / 1000
val endDate = mFilterOptions.endDate / 1000
for (transferDetail in transfersDetails) { for (transferDetail in transfersDetails) {
// Filter by transfer direction // Filter by transfer direction
if (transferDetail.direction) { // Transfer sent if (transferDetail.direction) { // Transfer sent
if (filterTransactionsDirection == 1) if (mFilterOptions.transactionsDirection == 1)
// Looking for received transfers only // Looking for received transfers only
continue continue
} else { // Transfer received } else { // Transfer received
if (filterTransactionsDirection == 2) if (mFilterOptions.transactionsDirection == 2)
// Looking for sent transactions only // Looking for sent transactions only
continue continue
} }
// Filter by date range // Filter by date range
if (!filterDateRangeAll && (transferDetail.date < filterStartDate || transferDetail.date > filterEndDate)) if (!mFilterOptions.dateRangeAll && (transferDetail.date < startDate ||
transferDetail.date > endDate))
continue continue
// Filter by asset // Filter by asset
if (!filterAssetAll && transferDetail.assetSymbol != filterAsset) if (!mFilterOptions.assetAll && transferDetail.assetSymbol != mFilterOptions.asset)
continue continue
// Filter by equivalent value // Filter by equivalent value
if (!filterEquivalentValueAll && ((transferDetail.fiatAmount ?: -1 ) < filterFromEquivalentValue if (!mFilterOptions.equivalentValueAll && ((transferDetail.fiatAmount ?: -1 ) < mFilterOptions.fromEquivalentValue
|| (transferDetail.fiatAmount ?: -1) > filterToEquivalentValue)) || (transferDetail.fiatAmount ?: -1) > mFilterOptions.toEquivalentValue))
continue continue
// Filter transactions sent to agorise // Filter transactions sent to agorise
if (filterAgoriseFees && transferDetail.to.equals("agorise")) if (mFilterOptions.agoriseFees && transferDetail.to.equals("agorise"))
continue continue
// Filter by search query // Filter by search query
val text = (transferDetail.from ?: "").toLowerCase() + (transferDetail.to ?: "").toLowerCase() val text = (transferDetail.from ?: "").toLowerCase() + (transferDetail.to ?: "").toLowerCase()
if (text.contains(filterQuery, ignoreCase = true)) { if (text.contains(mFilterOptions.query, ignoreCase = true)) {
filteredTransfersDetails.add(transferDetail) filteredTransfersDetails.add(transferDetail)
} }
} }
@ -214,28 +213,8 @@ 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( override fun onFilterOptionsSelected(filterOptions: FilterOptions) {
filterTransactionsDirection: Int, mFilterOptions = filterOptions
filterDateRangeAll: Boolean,
filterStartDate: Long,
filterEndDate: Long,
filterAssetAll: Boolean,
filterAsset: String,
filterEquivalentValueAll: Boolean,
filterFromEquivalentValue: Long,
filterToEquivalentValue: Long,
filterAgoriseFees: Boolean
) {
this.filterTransactionsDirection = filterTransactionsDirection
this.filterDateRangeAll = filterDateRangeAll
this.filterStartDate = filterStartDate / 1000
this.filterEndDate = filterEndDate / 1000
this.filterAssetAll = filterAssetAll
this.filterAsset = filterAsset
this.filterEquivalentValueAll = filterEquivalentValueAll
this.filterFromEquivalentValue = filterFromEquivalentValue
this.filterToEquivalentValue = filterToEquivalentValue
this.filterAgoriseFees = filterAgoriseFees
applyFilterOptions(true) applyFilterOptions(true)
} }
@ -244,7 +223,7 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele
if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE) if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
// Permission is not already granted // Permission is not already granted
requestPermissions(arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE), requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION) REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION)
} else { } else {
// Permission is already granted // Permission is already granted

View file

@ -0,0 +1,64 @@
package cy.agorise.bitsybitshareswallet.models
import android.os.Parcel
import android.os.Parcelable
/**
* Model that includes all the options to filter the transactions in the [TransactionsFragment]
*/
data class FilterOptions (
var query: String = "",
var transactionsDirection: Int = 0,
var dateRangeAll: Boolean = true,
var startDate: Long = 0L,
var endDate: Long = 0L,
var assetAll: Boolean = true,
var asset: String = "BTS",
var equivalentValueAll: Boolean = true,
var fromEquivalentValue: Long = 0L,
var toEquivalentValue: Long = 5000L,
var agoriseFees: Boolean = true
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readInt(),
parcel.readByte() != 0.toByte(),
parcel.readLong(),
parcel.readLong(),
parcel.readByte() != 0.toByte(),
parcel.readString(),
parcel.readByte() != 0.toByte(),
parcel.readLong(),
parcel.readLong(),
parcel.readByte() != 0.toByte()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(query)
parcel.writeInt(transactionsDirection)
parcel.writeByte(if (dateRangeAll) 1 else 0)
parcel.writeLong(startDate)
parcel.writeLong(endDate)
parcel.writeByte(if (assetAll) 1 else 0)
parcel.writeString(asset)
parcel.writeByte(if (equivalentValueAll) 1 else 0)
parcel.writeLong(fromEquivalentValue)
parcel.writeLong(toEquivalentValue)
parcel.writeByte(if (agoriseFees) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<FilterOptions> {
override fun createFromParcel(parcel: Parcel): FilterOptions {
return FilterOptions(parcel)
}
override fun newArray(size: Int): Array<FilterOptions?> {
return arrayOfNulls(size)
}
}
}

View file

@ -6,7 +6,7 @@ import androidx.lifecycle.LiveData
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
import cy.agorise.bitsybitshareswallet.repositories.TransferDetailRepository import cy.agorise.bitsybitshareswallet.repositories.TransferDetailRepository
class TransferDetailViewModel(application: Application) : AndroidViewModel(application) { class TransactionsViewModel(application: Application) : AndroidViewModel(application) {
private var mRepository = TransferDetailRepository(application) private var mRepository = TransferDetailRepository(application)
internal fun getAll(userId: String): LiveData<List<TransferDetail>> { internal fun getAll(userId: String): LiveData<List<TransferDetail>> {