Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primary report export csv #278

Open
wants to merge 7 commits into
base: primary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -42,6 +42,7 @@ import org.kodein.di.instance
import org.kodein.di.on
import java.io.File
import java.io.FileOutputStream
import java.io.FileWriter
import java.io.IOException
import kotlin.math.abs

Expand All @@ -50,9 +51,12 @@ interface ReportDetailFragmentEventHandler {
fun onClickAddToDashboard(report: ReportWithSeriesWithFilters)
fun onClickExportButton()
fun onClickAddAsTemplate(report: ReportWithSeriesWithFilters)
fun onClickExportImage()
fun onClickExportCSV()
}

class ReportDetailFragment : UstadDetailFragment<ReportWithSeriesWithFilters>(), ReportDetailView, ReportDetailFragmentEventHandler {
class ReportDetailFragment : UstadDetailFragment<ReportWithSeriesWithFilters>(), ReportDetailView,
ReportDetailFragmentEventHandler, BottomSheetOptionSelectedListener {

private var mBinding: FragmentReportDetailBinding? = null

Expand Down Expand Up @@ -284,6 +288,56 @@ class ReportDetailFragment : UstadDetailFragment<ReportWithSeriesWithFilters>(),
}

override fun onClickExportButton() {
val optionList =
listOf(
BottomSheetOption(R.drawable.ic_export,
requireContext().getString(R.string.image),
EXPORT_IMAGE),
BottomSheetOption(R.drawable.ic_export,
requireContext().getString(R.string.csv),
EXPORT_CSV))

val sheet = OptionsBottomSheetFragment(optionList, this)
sheet.show(childFragmentManager, sheet.tag)
}

override fun onBottomSheetOptionSelected(optionSelected: BottomSheetOption) {
when(optionSelected.optionCode){
EXPORT_IMAGE -> onClickExportImage()
EXPORT_CSV -> onClickExportCSV()
}
}

override fun onClickExportCSV() {
mPresenter?.generateCSVFile()
}

override fun shareCSVData(reportData: StringBuilder) {
val csvReportFilePath: String
//Create the file.
val output = File(context?.externalCacheDir,
System.currentTimeMillis().toString() + ".csv")
csvReportFilePath = output.getAbsolutePath()

val fileWriter = FileWriter(csvReportFilePath)
fileWriter.append(reportData)
fileWriter.close()

val fileUri = FileProvider.getUriForFile(requireContext(),
"${context?.packageName}.provider", output)

GlobalScope.launch(Dispatchers.IO) {
val intent = Intent(Intent.ACTION_SEND).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
putExtra(Intent.EXTRA_STREAM, fileUri)
type = "text/*"
}
startActivity(Intent.createChooser(intent, requireContext().getString(R.string.export)))
}
}

override fun onClickExportImage(){
GlobalScope.launch(Dispatchers.IO) {
val intent = Intent(Intent.ACTION_SEND).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
Expand Down Expand Up @@ -323,6 +377,9 @@ class ReportDetailFragment : UstadDetailFragment<ReportWithSeriesWithFilters>(),

companion object {

const val EXPORT_IMAGE = 1
const val EXPORT_CSV = 2

val DIFFUTIL_STATEMENT = object : DiffUtil.ItemCallback<StatementEntityWithDisplayDetails>() {
override fun areItemsTheSame(oldItem: StatementEntityWithDisplayDetails, newItem: StatementEntityWithDisplayDetails): Boolean {
return oldItem.statementUid == newItem.statementUid
Expand Down
7 changes: 7 additions & 0 deletions core/locale/main/values/strings_ui.xml
Expand Up @@ -1410,4 +1410,11 @@ Consent can be revoked anytime by using the link that was emailed. If you choose
If you are the parent, you need to login to your own existing account or create a new account.
</string>

<string name="image">Image</string>

<!-- CSV: Short for Comma Separated Values. This is a file format that can be used for exporting
reports that can be opened in spreadsheet software (e.g. Excel)
-->
<string name="csv">CSV</string>

</resources>
@@ -1,6 +1,8 @@
package com.ustadmobile.core.controller

import com.ustadmobile.core.db.UmAppDatabase
import com.ustadmobile.core.impl.UstadMobileSystemImpl
import com.ustadmobile.core.util.ext.ChartData
import com.ustadmobile.core.util.ext.generateChartData
import com.ustadmobile.core.util.ext.generateStatementList
import com.ustadmobile.core.util.safeParse
Expand Down Expand Up @@ -121,4 +123,90 @@ class ReportDetailPresenter(context: Any,
}
}

fun generateCSVFile() {
GlobalScope.launch {
val entityUid = arguments[ARG_ENTITY_UID]?.toLong() ?: 0L
val report = withTimeoutOrNull(2000) {
db.reportDao.findByUid(entityUid)
} ?: Report()


val series = if (!report.reportSeries.isNullOrEmpty()) {
safeParseList(
di,
ListSerializer(ReportSeries.serializer()),
ReportSeries::class, report.reportSeries ?: ""
)
} else {
listOf()
}
val reportWithFilter = ReportWithSeriesWithFilters(report, series)
var chartData =
db.generateChartData(reportWithFilter, context, systemImpl, loggedInPersonUid)
if(chartData.seriesData.isEmpty() && view.chartData != null &&
view.chartData?.seriesData?.isNotEmpty() == true){
chartData = view.chartData as ChartData
}

val csvString = StringBuilder()
//Add Report title
csvString.append(chartData?.reportWithFilters?.reportTitle)
val reportDesc = chartData?.reportWithFilters?.reportDescription ?: ""
//Add Report description (if it exists)
if (reportDesc.isNotEmpty()) {
csvString.append(" (")
csvString.append(reportDesc)
csvString.append(") ")
}
csvString.append("\n")
//Add Column names
val yAxisId =
chartData?.reportWithFilters?.reportSeriesWithFiltersList?.get(0)?.reportSeriesYAxis
?: 0
val xAxisId = chartData?.reportWithFilters?.xAxis ?: 0
val yLabel = UstadMobileSystemImpl.instance.getString(
ReportEditPresenter.YAxisOptions.values()
.filter { it.optionVal == yAxisId }[0].messageId, context
)
val xLabel = UstadMobileSystemImpl.instance.getString(
ReportEditPresenter.XAxisOptions.values()
.filter { it.optionVal == xAxisId }[0].messageId,
context
)
csvString.append("\n")
csvString.append(xLabel)
csvString.append(",")
csvString.append(yLabel)
csvString.append("\n")

for (everyData in chartData?.seriesData ?: emptyList()) {
//For every series, add Series name
csvString.append(everyData.series.reportSeriesName)
csvString.append("\n")

//Get chartData for series
for (everySeriesData in everyData.dataList) {
var formattedX =
chartData?.xAxisValueFormatter?.format(everySeriesData.xAxis?:"0")
if(formattedX == null){
formattedX = everySeriesData.xAxis
}
csvString.append(formattedX)

csvString.append(",")
csvString.append(everySeriesData.yAxis.toString())
csvString.append("\n")
}
}

csvString.append("\n")

withContext(doorMainDispatcher()) {
view.shareCSVData(csvString)
}

}

}

}
Expand Up @@ -13,6 +13,8 @@ interface ReportDetailView: UstadDetailView<ReportWithSeriesWithFilters> {

var chartData: ChartData?

fun shareCSVData(reportData: StringBuilder)

companion object {

const val VIEW_NAME = "ReportDetailView"
Expand Down
2 changes: 1 addition & 1 deletion runserver.bat
Expand Up @@ -9,4 +9,4 @@ if not exist app-ktor-server\application.conf (
)

cd app-ktor-server
java -jar app-ktor-server\build\libs\ustad-server-all.jar -config=application.conf
java -jar build\libs\ustad-server-all.jar -config=application.conf