167 lines
6.0 KiB
Kotlin
167 lines
6.0 KiB
Kotlin
package cy.agorise.bitsybitshareswallet.domain.usecase
|
|
|
|
import android.content.Context
|
|
import android.util.Log
|
|
import androidx.core.os.ConfigurationCompat
|
|
import androidx.documentfile.provider.DocumentFile
|
|
import com.pdfjet.*
|
|
import cy.agorise.bitsybitshareswallet.R
|
|
import cy.agorise.bitsybitshareswallet.database.joins.TransferDetail
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.withContext
|
|
import java.io.BufferedOutputStream
|
|
import java.text.SimpleDateFormat
|
|
import java.util.*
|
|
import kotlin.math.pow
|
|
|
|
class ExportTransactionsToPdfUseCase(private val applicationContext: Context) {
|
|
|
|
suspend operator fun invoke(
|
|
transactions: List<TransferDetail>,
|
|
folderDocumentFile: DocumentFile
|
|
) = withContext(Dispatchers.IO) { // TODO Inject Dispatcher
|
|
// Create the PDF file name
|
|
val fileName = applicationContext.resources.let {
|
|
"${it.getString(R.string.app_name)}-${it.getString(R.string.title_transactions)}.pdf"
|
|
}
|
|
|
|
// Obtains the path to store the PDF
|
|
val pdfDocUri = folderDocumentFile.createFile("application/pdf", fileName)?.uri
|
|
val contentResolver = applicationContext.contentResolver
|
|
val pdfOutputStream = contentResolver.openOutputStream(pdfDocUri!!, "w")
|
|
|
|
// Creates a new PDF object
|
|
val pdf = PDF(BufferedOutputStream(pdfOutputStream), Compliance.PDF_A_1B)
|
|
|
|
// Font used for the table headers
|
|
val f1 = Font(pdf, CoreFont.HELVETICA_BOLD).apply { size = 7f }
|
|
|
|
// Font used for the table contents
|
|
val f2 = Font(pdf, CoreFont.HELVETICA).apply { size = 7f }
|
|
|
|
// Creates a new PDF table
|
|
val table = Table()
|
|
|
|
// 2D array of cells used to populate the PDF table
|
|
val tableData = mutableListOf<List<Cell>>()
|
|
|
|
// Add column names/headers
|
|
val columnNames = intArrayOf(
|
|
R.string.title_from, R.string.title_to, R.string.title_memo, R.string.title_date,
|
|
R.string.title_time, R.string.title_amount, R.string.title_equivalent_value
|
|
)
|
|
|
|
val header = columnNames.map { columnName ->
|
|
Cell(f1, applicationContext.getString(columnName)).apply { setPadding(2f) }
|
|
}
|
|
|
|
// Add the table headers
|
|
tableData.add(header)
|
|
|
|
// Add the table contents
|
|
val locale = ConfigurationCompat.getLocales(applicationContext.resources.configuration)[0]
|
|
tableData.addAll(getData(transactions, f2, locale))
|
|
|
|
// Configure the PDF table
|
|
table.setData(tableData, Table.DATA_HAS_1_HEADER_ROWS)
|
|
table.setCellBordersWidth(0.2f)
|
|
// The A4 size has 595 points of width, with the below we are trying to assign the same
|
|
// width to all cells and also keep them centered.
|
|
for (i in 0..6) {
|
|
table.setColumnWidth(i, 65f)
|
|
}
|
|
table.wrapAroundCellText()
|
|
table.mergeOverlaidBorders()
|
|
|
|
// Populate the PDF table
|
|
while (table.hasMoreData()) {
|
|
// Configures the PDF page
|
|
val page = Page(pdf, Letter.PORTRAIT)
|
|
table.setLocation(45f, 30f)
|
|
table.drawOn(page)
|
|
}
|
|
|
|
pdf.close()
|
|
|
|
Log.d("ExportTransactionsToPdf", "PDF generated and saved")
|
|
}
|
|
|
|
private suspend fun getData(
|
|
transferDetails: List<TransferDetail>,
|
|
font: Font,
|
|
locale: Locale
|
|
): List<List<Cell>> = withContext(Dispatchers.IO) { // TODO Inject Dispatcher
|
|
|
|
val tableData = mutableListOf<List<Cell>>()
|
|
|
|
// Configure date and time formats to reuse in all the transfers
|
|
val dateFormat = SimpleDateFormat("MM-dd-yyyy", locale)
|
|
val timeFormat = SimpleDateFormat("HH:mm:ss", locale)
|
|
var date: Date
|
|
|
|
// Save all the transfers information
|
|
for ((index, transferDetail) in transferDetails.withIndex()) {
|
|
val cols = mutableListOf<String>()
|
|
|
|
date = Date(transferDetail.date * 1000)
|
|
|
|
cols.add(transferDetail.from ?: "") // From
|
|
cols.add(transferDetail.to ?: "") // To
|
|
cols.add(transferDetail.memo) // Memo
|
|
cols.add(dateFormat.format(date)) // Date
|
|
cols.add(timeFormat.format(date)) // Time
|
|
|
|
// Asset Amount
|
|
val assetPrecision = transferDetail.assetPrecision
|
|
val assetAmount = transferDetail.assetAmount / 10.0.pow(assetPrecision)
|
|
cols.add(
|
|
String.format(
|
|
"%.${assetPrecision}f %s",
|
|
assetAmount,
|
|
transferDetail.assetSymbol
|
|
)
|
|
)
|
|
|
|
// Fiat Equivalent
|
|
if (transferDetail.fiatAmount != null && transferDetail.fiatSymbol != null) {
|
|
val currency = Currency.getInstance(transferDetail.fiatSymbol)
|
|
val fiatAmount =
|
|
transferDetail.fiatAmount / 10.0.pow(currency.defaultFractionDigits)
|
|
cols.add(
|
|
String.format(
|
|
"%.${currency.defaultFractionDigits}f %s",
|
|
fiatAmount, currency.currencyCode
|
|
)
|
|
)
|
|
}
|
|
|
|
val row = cols.map { col ->
|
|
Cell(font, col).apply { setPadding(2f) }
|
|
}
|
|
|
|
tableData.add(row)
|
|
|
|
appendMissingCells(tableData, font)
|
|
|
|
// TODO update progress
|
|
}
|
|
|
|
tableData
|
|
}
|
|
|
|
private fun appendMissingCells(tableData: List<List<Cell>>, font: Font) {
|
|
val firstRow = tableData[0]
|
|
val numOfColumns = firstRow.size
|
|
for (i in tableData.indices) {
|
|
val dataRow = tableData[i] as ArrayList<Cell>
|
|
val dataRowColumns = dataRow.size
|
|
if (dataRowColumns < numOfColumns) {
|
|
for (j in 0 until numOfColumns - dataRowColumns) {
|
|
dataRow.add(Cell(font))
|
|
}
|
|
dataRow[dataRowColumns - 1].colSpan = numOfColumns - dataRowColumns + 1
|
|
}
|
|
}
|
|
}
|
|
}
|