From caf909e45360927285126026dbc153776fa80874 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Tue, 5 Feb 2019 11:46:27 -0600 Subject: [PATCH] Added a task to generate in the background the CSV representation of the filtered transactions with the same columns as the PDF export option. --- .../fragments/TransactionsFragment.kt | 9 +- .../utils/CSVGenerationTask.kt | 97 +++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/cy/agorise/bitsybitshareswallet/utils/CSVGenerationTask.kt diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/TransactionsFragment.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/TransactionsFragment.kt index eaae41e..a9b3a1a 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/TransactionsFragment.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/fragments/TransactionsFragment.kt @@ -20,10 +20,7 @@ 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.utils.BounceTouchListener -import cy.agorise.bitsybitshareswallet.utils.Constants -import cy.agorise.bitsybitshareswallet.utils.PDFGeneratorTask -import cy.agorise.bitsybitshareswallet.utils.toast +import cy.agorise.bitsybitshareswallet.utils.* import cy.agorise.bitsybitshareswallet.viewmodels.TransferDetailViewModel import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable @@ -32,6 +29,7 @@ import java.io.File import java.util.* import java.util.concurrent.TimeUnit import kotlin.collections.ArrayList +import kotlin.math.exp class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSelectedListener { @@ -280,6 +278,9 @@ class TransactionsFragment : Fragment(), FilterOptionsDialog.OnFilterOptionsSele if (exportPDF) activity?.let { PDFGeneratorTask(it).execute(filteredTransfersDetails) } + if (exportCSV) + activity?.let { CSVGenerationTask(it).execute(filteredTransfersDetails) } + } override fun onDestroy() { diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/CSVGenerationTask.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/CSVGenerationTask.kt new file mode 100644 index 0000000..7dd9f69 --- /dev/null +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/utils/CSVGenerationTask.kt @@ -0,0 +1,97 @@ +package cy.agorise.bitsybitshareswallet.utils + +import android.content.Context +import android.os.AsyncTask +import android.os.Environment +import android.util.Log +import com.opencsv.CSVWriter +import cy.agorise.bitsybitshareswallet.R +import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail +import java.io.File +import java.io.FileWriter +import java.lang.ref.WeakReference +import java.text.SimpleDateFormat +import java.util.* + +/** + * AsyncTask subclass used to move the PDF generation procedure to a background thread + * and inform the UI of the progress. + */ +class CSVGenerationTask(context: Context) : AsyncTask, Int, String>() { + + companion object { + private const val TAG = "CSVGenerationTask" + } + + private val mContext: WeakReference = WeakReference(context) + + override fun doInBackground(vararg params: List): String { + return createCSVDocument(params[0]) + } + + private fun createCSVDocument(transferDetails: List): String { + return try { + // Create and configure a new CSV file to save the transfers list + val externalStorageFolder = Environment.getExternalStorageDirectory().absolutePath + File.separator + + Constants.EXTERNAL_STORAGE_FOLDER + val fileName = mContext.get()?.resources?.let { + "${it.getString(R.string.app_name)}-${it.getString(R.string.title_transactions)}"} + ".csv" + val file = File(externalStorageFolder, fileName) + file.createNewFile() + val csvWriter = CSVWriter(FileWriter(file)) + + // Add the table header + val row = Array(7) {""} // Array initialized with empty strings + val columnNames = arrayOf(R.string.title_from, R.string.title_to, R.string.title_memo, R.string.title_date, + R.string.title_time, R.string.title_asset_amount, R.string.title_fiat_equivalent) + for ((i, columnName) in columnNames.withIndex()) { + row[i] = mContext.get()?.getString(columnName) ?: "" + } + csvWriter.writeNext(row) + + // Configure date and time formats to reuse in all the transfers + val locale = mContext.get()?.resources?.configuration?.locale + val calendar = Calendar.getInstance() + val dateFormat = SimpleDateFormat("MM-dd-yyyy", locale) + val timeFormat = SimpleDateFormat("HH:MM:ss", locale) + + // Save all the transfers information + for ( (index, transferDetail) in transferDetails.withIndex()) { + calendar.timeInMillis = transferDetail.date * 1000 + val date = calendar.time + + row[0] = transferDetail.from ?: "" // From + row[1] = transferDetail.to ?: "" // To + row[2] = transferDetail.memo // Memo + row[3] = dateFormat.format(date) // Date + row[4] = timeFormat.format(date) // Time + + // Asset Amount + val assetPrecision = transferDetail.assetPrecision + val assetAmount = transferDetail.assetAmount.toDouble() / Math.pow(10.0, assetPrecision.toDouble()) + row[5] = String.format("%.${assetPrecision}f %s", assetAmount, transferDetail.assetSymbol) + + // Fiat Equivalent TODO add once Nelson finishes + row[6] = "" + + csvWriter.writeNext(row) + + // TODO update progress + } + + csvWriter.close() + "CSV generated and saved: ${file.absolutePath}" + } catch (e: Exception) { + Log.e(TAG, "Exception while trying to generate a CSV. Msg: " + e.message) + "Unable to generate CSV. Please retry. Error: ${e.message}" + } + } + + override fun onProgressUpdate(values: Array) { + // TODO show progress + } + + override fun onPostExecute(message: String) { + mContext.get()?.toast(message) + } +} \ No newline at end of file