diff --git a/core/data/src/main/java/com/mifos/core/data/di/DataModule.kt b/core/data/src/main/java/com/mifos/core/data/di/DataModule.kt index 120dca3e71a..c67f986b3d8 100644 --- a/core/data/src/main/java/com/mifos/core/data/di/DataModule.kt +++ b/core/data/src/main/java/com/mifos/core/data/di/DataModule.kt @@ -14,6 +14,7 @@ import com.mifos.core.data.repository.LoanAccountRepository import com.mifos.core.data.repository.NewIndividualCollectionSheetRepository import com.mifos.core.data.repository.PathTrackingRepository import com.mifos.core.data.repository.ReportCategoryRepository +import com.mifos.core.data.repository.ReportDetailRepository import com.mifos.core.data.repository_imp.CenterDetailsRepositoryImp import com.mifos.core.data.repository_imp.CenterListRepositoryImp import com.mifos.core.data.repository_imp.CheckerInboxRepositoryImp @@ -27,6 +28,7 @@ import com.mifos.core.data.repository_imp.LoanAccountRepositoryImp import com.mifos.core.data.repository_imp.NewIndividualCollectionSheetRepositoryImp import com.mifos.core.data.repository_imp.PathTrackingRepositoryImp import com.mifos.core.data.repository_imp.ReportCategoryRepositoryImp +import com.mifos.core.data.repository_imp.ReportDetailRepositoryImp import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -74,6 +76,9 @@ abstract class DataModule { @Binds internal abstract fun bindClientIdentifiersRepository(impl: ClientIdentifiersRepositoryImp): ClientIdentifiersRepository + @Binds + internal abstract fun bindReportDetailRepository(impl: ReportDetailRepositoryImp): ReportDetailRepository + @Binds internal abstract fun bindLoanAccountRepository(impl: LoanAccountRepositoryImp): LoanAccountRepository } \ No newline at end of file diff --git a/core/data/src/main/java/com/mifos/core/data/repository/ReportDetailRepository.kt b/core/data/src/main/java/com/mifos/core/data/repository/ReportDetailRepository.kt new file mode 100644 index 00000000000..798718c5ae0 --- /dev/null +++ b/core/data/src/main/java/com/mifos/core/data/repository/ReportDetailRepository.kt @@ -0,0 +1,30 @@ +package com.mifos.core.data.repository + +import com.mifos.core.objects.runreports.FullParameterListResponse + +/** + * Created by Aditya Gupta on 12/08/23. + */ +interface ReportDetailRepository { + + suspend fun getReportFullParameterList( + reportName: String, parameterType: Boolean + ): FullParameterListResponse + + suspend fun getReportParameterDetails( + parameterName: String, parameterType: Boolean + ): FullParameterListResponse + + suspend fun getRunReportOffices( + parameterName: String, officeId: Int, parameterType: Boolean + ): FullParameterListResponse + + suspend fun getRunReportProduct( + parameterName: String, currency: String, parameterType: Boolean + ): FullParameterListResponse + + suspend fun getRunReportWithQuery( + reportName: String, options: Map + ): FullParameterListResponse + +} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailRepositoryImp.kt b/core/data/src/main/java/com/mifos/core/data/repository_imp/ReportDetailRepositoryImp.kt similarity index 55% rename from mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailRepositoryImp.kt rename to core/data/src/main/java/com/mifos/core/data/repository_imp/ReportDetailRepositoryImp.kt index 5d3153f3876..910e545ffe2 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailRepositoryImp.kt +++ b/core/data/src/main/java/com/mifos/core/data/repository_imp/ReportDetailRepositoryImp.kt @@ -1,8 +1,8 @@ -package com.mifos.mifosxdroid.online.runreports.reportdetail +package com.mifos.core.data.repository_imp +import com.mifos.core.data.repository.ReportDetailRepository import com.mifos.core.network.datamanager.DataManagerRunReport import com.mifos.core.objects.runreports.FullParameterListResponse -import rx.Observable import javax.inject.Inject /** @@ -11,40 +11,40 @@ import javax.inject.Inject class ReportDetailRepositoryImp @Inject constructor(private val dataManager: DataManagerRunReport) : ReportDetailRepository { - override fun getReportFullParameterList( - reportName: String?, + override suspend fun getReportFullParameterList( + reportName: String, parameterType: Boolean - ): Observable { + ): FullParameterListResponse { return dataManager.getReportFullParameterList(reportName, parameterType) } - override fun getReportParameterDetails( - parameterName: String?, + override suspend fun getReportParameterDetails( + parameterName: String, parameterType: Boolean - ): Observable { + ): FullParameterListResponse { return dataManager.getReportParameterDetails(parameterName, parameterType) } - override fun getRunReportOffices( - parameterName: String?, + override suspend fun getRunReportOffices( + parameterName: String, officeId: Int, parameterType: Boolean - ): Observable { + ): FullParameterListResponse { return dataManager.getRunReportOffices(parameterName, officeId, parameterType) } - override fun getRunReportProduct( - parameterName: String?, - currency: String?, + override suspend fun getRunReportProduct( + parameterName: String, + currency: String, parameterType: Boolean - ): Observable { + ): FullParameterListResponse { return dataManager.getRunReportProduct(parameterName, currency, parameterType) } - override fun getRunReportWithQuery( - reportName: String?, - options: Map - ): Observable { + override suspend fun getRunReportWithQuery( + reportName: String, + options: Map + ): FullParameterListResponse { return dataManager.getRunReportWithQuery(reportName, options) } } \ No newline at end of file diff --git a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosPermissionBox.kt b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosPermissionBox.kt index bfa8c32724c..c4763c68e89 100644 --- a/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosPermissionBox.kt +++ b/core/designsystem/src/main/java/com/mifos/core/designsystem/component/MifosPermissionBox.kt @@ -83,10 +83,11 @@ fun PermissionBox( if (!isGranted) { shouldShowPermissionRationale = requiredPermissions.all { - ActivityCompat.shouldShowRequestPermissionRationale( - context as Activity, - it - ) + (context as? Activity)?.let { it1 -> + ActivityCompat.shouldShowRequestPermissionRationale( + it1, it + ) + } == false } } shouldDirectUserToApplicationSettings = @@ -114,7 +115,7 @@ fun PermissionBox( if (shouldShowPermissionRationale) { MifosDialogBox( - showDialogState = shouldShowPermissionRationale, + showDialogState = shouldShowPermissionRationale, onDismiss = { shouldShowPermissionRationale = false }, title = title, message = description, diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportFullParameterListUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportFullParameterListUseCase.kt new file mode 100644 index 00000000000..d1abb024e2b --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportFullParameterListUseCase.kt @@ -0,0 +1,24 @@ +package com.mifos.core.domain.use_cases + +import com.mifos.core.common.utils.Resource +import com.mifos.core.data.repository.ReportDetailRepository +import com.mifos.core.objects.runreports.FullParameterListResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetReportFullParameterListUseCase @Inject constructor(private val repository: ReportDetailRepository) { + + suspend operator fun invoke( + reportName: String, + parameterType: Boolean + ): Flow> = flow { + try { + emit(Resource.Loading()) + val response = repository.getReportFullParameterList(reportName, parameterType) + emit(Resource.Success(response)) + } catch (exception: Exception) { + emit(Resource.Error(exception.message.toString())) + } + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportParameterDetailsUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportParameterDetailsUseCase.kt new file mode 100644 index 00000000000..498184cf29c --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportParameterDetailsUseCase.kt @@ -0,0 +1,24 @@ +package com.mifos.core.domain.use_cases + +import com.mifos.core.common.utils.Resource +import com.mifos.core.data.repository.ReportDetailRepository +import com.mifos.core.objects.runreports.FullParameterListResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetReportParameterDetailsUseCase @Inject constructor(private val repository: ReportDetailRepository) { + + suspend operator fun invoke( + parameterName: String, + parameterType: Boolean + ): Flow> = flow { + try { + emit(Resource.Loading()) + val response = repository.getReportParameterDetails(parameterName, parameterType) + emit(Resource.Success(response)) + } catch (exception: Exception) { + emit(Resource.Error(exception.message.toString())) + } + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportOfficesUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportOfficesUseCase.kt new file mode 100644 index 00000000000..b55426491e9 --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportOfficesUseCase.kt @@ -0,0 +1,26 @@ +package com.mifos.core.domain.use_cases + +import com.mifos.core.common.utils.Resource +import com.mifos.core.data.repository.ReportDetailRepository +import com.mifos.core.objects.runreports.FullParameterListResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetRunReportOfficesUseCase @Inject constructor(private val repository: ReportDetailRepository) { + + suspend operator fun invoke( + parameterName: String, + officeId: Int, + parameterType: Boolean + ): Flow> = flow { + try { + emit(Resource.Loading()) + val response = repository.getRunReportOffices(parameterName, officeId, parameterType) + emit(Resource.Success(response)) + + } catch (exception: Exception) { + emit(Resource.Error(exception.message.toString())) + } + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportProductUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportProductUseCase.kt new file mode 100644 index 00000000000..90cf097f8ad --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportProductUseCase.kt @@ -0,0 +1,25 @@ +package com.mifos.core.domain.use_cases + +import com.mifos.core.common.utils.Resource +import com.mifos.core.data.repository.ReportDetailRepository +import com.mifos.core.objects.runreports.FullParameterListResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetRunReportProductUseCase @Inject constructor(private val repository: ReportDetailRepository) { + + suspend operator fun invoke( + parameterName: String, + currency: String, + parameterType: Boolean + ): Flow> = flow { + try { + emit(Resource.Loading()) + val response = repository.getRunReportProduct(parameterName, currency, parameterType) + emit(Resource.Success(response)) + } catch (exception: Exception) { + emit(Resource.Error(exception.message.toString())) + } + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportWithQueryUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportWithQueryUseCase.kt new file mode 100644 index 00000000000..da64cddaf72 --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetRunReportWithQueryUseCase.kt @@ -0,0 +1,24 @@ +package com.mifos.core.domain.use_cases + +import com.mifos.core.common.utils.Resource +import com.mifos.core.data.repository.ReportDetailRepository +import com.mifos.core.objects.runreports.FullParameterListResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetRunReportWithQueryUseCase @Inject constructor(private val repository: ReportDetailRepository) { + + suspend operator fun invoke( + reportName: String, + options: Map + ): Flow> = flow { + try { + emit(Resource.Loading()) + val response = repository.getRunReportWithQuery(reportName, options) + emit(Resource.Success(response)) + } catch (exception: Exception) { + emit(Resource.Error(exception.message.toString())) + } + } +} \ No newline at end of file diff --git a/core/network/src/main/java/com/mifos/core/network/datamanager/DataManagerRunReport.kt b/core/network/src/main/java/com/mifos/core/network/datamanager/DataManagerRunReport.kt index ee39659f9d1..e6b71de0470 100644 --- a/core/network/src/main/java/com/mifos/core/network/datamanager/DataManagerRunReport.kt +++ b/core/network/src/main/java/com/mifos/core/network/datamanager/DataManagerRunReport.kt @@ -4,7 +4,6 @@ import com.mifos.core.network.BaseApiManager import com.mifos.core.objects.group.CenterInfo import com.mifos.core.objects.runreports.FullParameterListResponse import com.mifos.core.objects.runreports.client.ClientReportTypeItem -import rx.Observable import javax.inject.Inject import javax.inject.Singleton @@ -24,23 +23,23 @@ class DataManagerRunReport @Inject constructor(val mBaseApiManager: BaseApiManag ) } - fun getReportFullParameterList( - reportName: String?, parameterType: Boolean - ): Observable { + suspend fun getReportFullParameterList( + reportName: String, parameterType: Boolean + ): FullParameterListResponse { return mBaseApiManager.runReportsService .getReportFullParameterList(reportName, parameterType) } - fun getReportParameterDetails( - parameterName: String?, parameterType: Boolean - ): Observable { + suspend fun getReportParameterDetails( + parameterName: String, parameterType: Boolean + ): FullParameterListResponse { return mBaseApiManager.runReportsService .getReportParameterDetails(parameterName, parameterType) } - fun getRunReportWithQuery( - reportName: String?, options: Map - ): Observable { + suspend fun getRunReportWithQuery( + reportName: String, options: Map + ): FullParameterListResponse { return mBaseApiManager.runReportsService .getRunReportWithQuery(reportName, options) } @@ -53,9 +52,9 @@ class DataManagerRunReport @Inject constructor(val mBaseApiManager: BaseApiManag .getCenterSummaryInfo(centerId, genericResultSet) } - fun getRunReportOffices( - parameterName: String?, officeId: Int, parameterType: Boolean - ): Observable { + suspend fun getRunReportOffices( + parameterName: String, officeId: Int, parameterType: Boolean + ): FullParameterListResponse { return mBaseApiManager.runReportsService.getReportOffice( parameterName, officeId, @@ -63,9 +62,9 @@ class DataManagerRunReport @Inject constructor(val mBaseApiManager: BaseApiManag ) } - fun getRunReportProduct( - parameterName: String?, currency: String?, parameterType: Boolean - ): Observable { + suspend fun getRunReportProduct( + parameterName: String, currency: String, parameterType: Boolean + ): FullParameterListResponse { return mBaseApiManager.runReportsService.getReportProduct( parameterName, currency, diff --git a/core/network/src/main/java/com/mifos/core/network/services/RunReportsService.kt b/core/network/src/main/java/com/mifos/core/network/services/RunReportsService.kt index 1501c4b141f..7ea0e277402 100644 --- a/core/network/src/main/java/com/mifos/core/network/services/RunReportsService.kt +++ b/core/network/src/main/java/com/mifos/core/network/services/RunReportsService.kt @@ -8,7 +8,6 @@ import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query import retrofit2.http.QueryMap -import rx.Observable /** * Created by Rajan Maurya on 05/02/17. @@ -35,10 +34,10 @@ interface RunReportsService { * @return FullParameterListResponse */ @GET(APIEndPoint.RUN_REPORTS + "/FullParameterList") - fun getReportFullParameterList( - @Query("R_reportListing") reportName: String?, + suspend fun getReportFullParameterList( + @Query("R_reportListing") reportName: String, @Query("parameterType") parameterType: Boolean - ): Observable + ): FullParameterListResponse /** * Endpoint to fetch the details for a particular parameter. @@ -47,24 +46,24 @@ interface RunReportsService { * @return */ @GET(APIEndPoint.RUN_REPORTS + "/{path}") - fun getReportParameterDetails( - @Path("path") parameterName: String?, + suspend fun getReportParameterDetails( + @Path("path") parameterName: String, @Query("parameterType") parameterType: Boolean - ): Observable + ): FullParameterListResponse @GET(APIEndPoint.RUN_REPORTS + "/{path}") - fun getReportOffice( - @Path("path") parameterName: String?, + suspend fun getReportOffice( + @Path("path") parameterName: String, @Query("R_officeId") office: Int, @Query("parameterType") parameterType: Boolean - ): Observable + ): FullParameterListResponse @GET(APIEndPoint.RUN_REPORTS + "/{path}") - fun getReportProduct( - @Path("path") parameterName: String?, - @Query("R_currencyId") currency: String?, + suspend fun getReportProduct( + @Path("path") parameterName: String, + @Query("R_currencyId") currency: String, @Query("parameterType") parameterType: Boolean - ): Observable + ): FullParameterListResponse /** * Endpoint to retrieve final Report based on the parameters. @@ -73,10 +72,10 @@ interface RunReportsService { * @return */ @GET(APIEndPoint.RUN_REPORTS + "/{path}") - fun getRunReportWithQuery( - @Path("path") reportName: String?, - @QueryMap options: Map? - ): Observable + suspend fun getRunReportWithQuery( + @Path("path") reportName: String, + @QueryMap options: Map + ): FullParameterListResponse @GET(APIEndPoint.RUN_REPORTS + "/GroupSummaryCounts") suspend fun getCenterSummaryInfo( diff --git a/feature/report/src/main/java/com/mifos/feature/report/report/ReportScreen.kt b/feature/report/src/main/java/com/mifos/feature/report/report/ReportScreen.kt new file mode 100644 index 00000000000..6255a4e233a --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/report/ReportScreen.kt @@ -0,0 +1,180 @@ +package com.mifos.feature.report.report + +import android.Manifest +import android.os.Build +import android.os.Environment +import android.widget.Toast +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat.getString +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.mifos.core.designsystem.component.MifosScaffold +import com.mifos.core.designsystem.component.PermissionBox +import com.mifos.core.designsystem.icon.MifosIcons +import com.mifos.core.designsystem.theme.Black +import com.mifos.core.designsystem.theme.White +import com.mifos.core.objects.runreports.FullParameterListResponse +import com.mifos.feature.report.R +import kotlinx.coroutines.launch + +@Composable +fun ReportScreen( + report: FullParameterListResponse, + onBackPressed: () -> Unit +) { + + val viewModel: ReportViewModel = hiltViewModel() + val state by viewModel.reportUiState.collectAsStateWithLifecycle() + val context = LocalContext.current + + ReportScreen( + state = state, + report = report, + onBackPressed = onBackPressed, + exportReport = { + val reportDirectoryPath = + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + .toString() + getString(context, R.string.feature_report_export_csv_directory) + viewModel.exportCsv( + report = report, + reportDirectoryPath = reportDirectoryPath + ) + } + ) +} + + +@Composable +fun ReportScreen( + state: ReportUiState, + report: FullParameterListResponse, + onBackPressed: () -> Unit, + exportReport: () -> Unit +) { + + val context = LocalContext.current + val scope = rememberCoroutineScope() + val snackbarHostState = remember { SnackbarHostState() } + var checkPermission by remember { mutableStateOf(false) } + + + when (state) { + is ReportUiState.Initial -> Unit + is ReportUiState.Message -> { + Toast.makeText(context, stringResource(id = state.message), Toast.LENGTH_SHORT).show() + } + } + + if (checkPermission) { + PermissionBox( + requiredPermissions = if (Build.VERSION.SDK_INT >= 33) { + listOf(Manifest.permission.READ_MEDIA_IMAGES) + } else { + listOf( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + }, + title = R.string.feature_report_permission_required, + description = R.string.feature_report_external_approve_permission_description, + confirmButtonText = R.string.feature_report_proceed, + dismissButtonText = R.string.feature_report_dismiss, + onGranted = { + LaunchedEffect(key1 = Unit) { + scope.launch { + exportReport() + } + } + } + ) + } + + MifosScaffold( + icon = MifosIcons.arrowBack, + title = stringResource(R.string.feature_report_title), + onBackPressed = onBackPressed, + actions = { + TextButton( + onClick = { + checkPermission = true + }, + colors = ButtonDefaults.textButtonColors(White) + ) { + Text(text = stringResource(id = R.string.feature_report_export_csv), color = Black) + } + }, + snackbarHostState = snackbarHostState + ) { paddingValues -> + + Column( + modifier = Modifier + .padding(paddingValues) + .verticalScroll(rememberScrollState()) + ) { + LazyRow { + itemsIndexed(report.columnHeaders.map { it.columnName }) { index, columnName -> + Column { + Text( + modifier = Modifier.padding(8.dp), + text = columnName, + style = TextStyle( + fontWeight = FontWeight.Bold + ) + ) + report.data.map { it.row }.forEach { + Text(text = it[index] ?: "-", modifier = Modifier.padding(8.dp)) + } + } + } + } + } + } +} + +class ReportUiStateProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + ReportUiState.Initial, + ReportUiState.Message(R.string.feature_report_export_csv) + ) + +} + +@Preview(showBackground = true) +@Composable +private fun ReportScreenPreview( + @PreviewParameter(ReportUiStateProvider::class) state: ReportUiState +) { + ReportScreen( + state = state, + report = FullParameterListResponse(emptyList(), emptyList()), + onBackPressed = { }, + exportReport = { } + ) +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/report/ReportUiState.kt b/feature/report/src/main/java/com/mifos/feature/report/report/ReportUiState.kt new file mode 100644 index 00000000000..7e525337825 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/report/ReportUiState.kt @@ -0,0 +1,8 @@ +package com.mifos.feature.report.report + +sealed class ReportUiState { + + data object Initial : ReportUiState() + + data class Message(val message: Int) : ReportUiState() +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/report/ReportViewModel.kt b/feature/report/src/main/java/com/mifos/feature/report/report/ReportViewModel.kt new file mode 100644 index 00000000000..37dfa344f98 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/report/ReportViewModel.kt @@ -0,0 +1,69 @@ +package com.mifos.feature.report.report + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mifos.core.objects.runreports.FullParameterListResponse +import com.mifos.feature.report.R +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import java.io.File +import java.io.FileWriter +import javax.inject.Inject + +@HiltViewModel +class ReportViewModel @Inject constructor() : ViewModel() { + + private val _reportUiState = MutableStateFlow(ReportUiState.Initial) + val reportUiState = _reportUiState.asStateFlow() + + fun exportCsv(report: FullParameterListResponse, reportDirectoryPath: String) = + viewModelScope.launch(Dispatchers.IO) { + + _reportUiState.value = ReportUiState.Message(R.string.feature_report_export_started) + val timestamp = System.currentTimeMillis() + val reportPath = "$reportDirectoryPath$timestamp.csv" + val reportDirectory = File(reportDirectoryPath) + + if (!reportDirectory.exists()) { + val makeRequiredDirectories = reportDirectory.mkdirs() + if (!makeRequiredDirectories) { + _reportUiState.value = + ReportUiState.Message(R.string.feature_report_unable_to_create_directory) + } + } + + try { + + val fileWriter = FileWriter(reportPath) + + // write headers + val columnSize = report.columnHeaders.size + var count = 1 + for (header in report.columnHeaders) { + fileWriter.append(header.columnName) + if (count == columnSize) { + fileWriter.append("\n") + } else { + fileWriter.append(",") + } + count++ + } + + // write row data + for (row in report.data) { + fileWriter.append(java.lang.String.join(",", row.row)) + fileWriter.append("\n") + } + fileWriter.flush() + fileWriter.close() + } catch (e: Exception) { + _reportUiState.value = + ReportUiState.Message(R.string.feature_report_unable_to_export) + } + _reportUiState.value = + ReportUiState.Message(R.string.feature_report_exported_successfully) + } +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailScreen.kt b/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailScreen.kt new file mode 100644 index 00000000000..629e40efbdb --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailScreen.kt @@ -0,0 +1,616 @@ +package com.mifos.feature.report.report_detail + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.mifos.core.common.utils.Constants +import com.mifos.core.designsystem.component.MifosCircularProgress +import com.mifos.core.designsystem.component.MifosScaffold +import com.mifos.core.designsystem.component.MifosSweetError +import com.mifos.core.designsystem.component.MifosTextFieldDropdown +import com.mifos.core.designsystem.icon.MifosIcons +import com.mifos.core.designsystem.theme.Black +import com.mifos.core.designsystem.theme.BlueSecondary +import com.mifos.core.designsystem.theme.DarkGray +import com.mifos.core.designsystem.theme.White +import com.mifos.core.objects.runreports.DataRow +import com.mifos.core.objects.runreports.FullParameterListResponse +import com.mifos.core.objects.runreports.client.ClientReportTypeItem +import com.mifos.feature.report.R + +@Composable +fun ReportDetailScreen( + reportItem: ClientReportTypeItem, + onBackPressed: () -> Unit, + runReport: (FullParameterListResponse) -> Unit +) { + + val viewModel: ReportDetailViewModel = hiltViewModel() + val state by viewModel.reportDetailUiState.collectAsStateWithLifecycle() + val reportParameterList by viewModel.reportParameterList.collectAsStateWithLifecycle() + val reportDetail by viewModel.reportDetail.collectAsStateWithLifecycle() + val reportOffices by viewModel.reportOffices.collectAsStateWithLifecycle() + val reportProducts by viewModel.reportProducts.collectAsStateWithLifecycle() + val runReportDetail by viewModel.runReport.collectAsStateWithLifecycle() + var runReportEnable by remember { mutableStateOf(false) } + + LaunchedEffect(runReportDetail) { + runReportDetail?.let { + if (runReportEnable) { + runReport(it) + } + } + } + + var officeId by rememberSaveable { mutableIntStateOf(0) } + var currencyId by rememberSaveable { mutableStateOf("") } + + var officeList by rememberSaveable { mutableStateOf(emptyList()) } + var loanPurposeList by rememberSaveable { mutableStateOf(emptyList()) } + var fundList by rememberSaveable { mutableStateOf(emptyList()) } + var currencyList by rememberSaveable { mutableStateOf(emptyList()) } + var parCalculatorList by rememberSaveable { mutableStateOf(emptyList()) } + var savingsAccountDepositList by rememberSaveable { mutableStateOf(emptyList()) } + var glAccountList by rememberSaveable { mutableStateOf(emptyList()) } + var obligationDateList by rememberSaveable { mutableStateOf(emptyList()) } + + LaunchedEffect(reportDetail) { + when (reportDetail.second) { + Constants.LOAN_OFFICER_ID_SELECT -> { + viewModel.fetchOffices(reportDetail.second, officeId, true) + } + + Constants.LOAN_PRODUCT_ID_SELECT -> { + viewModel.fetchProduct(reportDetail.second, currencyId, true) + } + + Constants.LOAN_PURPOSE_ID_SELECT -> { + loanPurposeList = reportDetail.first + } + + Constants.FUND_ID_SELECT -> { + fundList = reportDetail.first + } + + Constants.CURRENCY_ID_SELECT -> { + currencyId = reportDetail.first.first().row.first() + currencyList = reportDetail.first + viewModel.fetchProduct(Constants.LOAN_PRODUCT_ID_SELECT, currencyId, true) + } + + Constants.OFFICE_ID_SELECT -> { + officeList = reportDetail.first + officeId = reportDetail.first.first().row.first().toInt() + viewModel.fetchOffices(Constants.LOAN_OFFICER_ID_SELECT, officeId, true) + } + + Constants.PAR_TYPE_SELECT -> { + parCalculatorList = reportDetail.first + } + + Constants.SAVINGS_ACCOUNT_SUB_STATUS -> { + savingsAccountDepositList = reportDetail.first + } + + Constants.SELECT_GL_ACCOUNT_NO -> { + glAccountList = reportDetail.first + } + + Constants.OBLIG_DATE_TYPE_SELECT -> { + obligationDateList = reportDetail.first + } + } + } + + LaunchedEffect(Unit) { + val reportName = "'" + reportItem.report_name + "'" + viewModel.fetchFullParameterList(reportName, true) + } + + LaunchedEffect(reportParameterList) { + reportParameterList.forEach { + viewModel.fetchParameterDetails(it.row.first(), true) + } + } + + ReportDetailScreen( + reportItem = reportItem, + state = state, + onBackPressed = onBackPressed, + onRetry = {}, + officeList = officeList, + loanPurposeList = loanPurposeList, + fundList = fundList, + currencyList = currencyList, + parCalculatorList = parCalculatorList, + savingsAccountDepositList = savingsAccountDepositList, + glAccountList = glAccountList, + obligationDateList = obligationDateList, + reportOffices = reportOffices, + reportProducts = reportProducts, + runReport = { mapQuery -> + runReportEnable = true + reportItem.report_name?.let { + viewModel.fetchRunReportWithQuery(it, mapQuery) + } + } + ) + +} + +@Composable +fun ReportDetailScreen( + reportItem: ClientReportTypeItem, + state: ReportDetailUiState, + onBackPressed: () -> Unit, + onRetry: () -> Unit, + officeList: List, + loanPurposeList: List, + fundList: List, + currencyList: List, + parCalculatorList: List, + savingsAccountDepositList: List, + glAccountList: List, + obligationDateList: List, + reportOffices: List, + reportProducts: List, + runReport: (MutableMap) -> Unit +) { + val snackbarHostState = remember { SnackbarHostState() } + val runReportDetail by rememberSaveable { mutableStateOf>(HashMap()) } + + + MifosScaffold( + icon = MifosIcons.arrowBack, + title = stringResource(id = R.string.feature_report_details), + onBackPressed = onBackPressed, + actions = { + TextButton( + onClick = { runReport(runReportDetail) }, + colors = ButtonDefaults.textButtonColors(White) + ) { + Text(text = stringResource(id = R.string.feature_report_run_report), color = Black) + } + }, + snackbarHostState = snackbarHostState + ) { paddingValues -> + Column(modifier = Modifier.padding(paddingValues)) { + + when (state) { + is ReportDetailUiState.Error -> MifosSweetError(message = stringResource(id = state.message)) { + onRetry() + } + + + is ReportDetailUiState.Loading -> MifosCircularProgress() + + ReportDetailUiState.ParameterDetailsSuccess -> { + RunReportContent( + reportItem = reportItem, + officeList = officeList, + loanPurposeList = loanPurposeList, + fundList = fundList, + currencyList = currencyList, + parCalculatorList = parCalculatorList, + savingsAccountDepositList = savingsAccountDepositList, + glAccountList = glAccountList, + obligationDateList = obligationDateList, + reportOffices = reportOffices, + reportProducts = reportProducts, + runReportDetail = runReportDetail + ) + } + } + } + } +} + +@Composable +fun RunReportContent( + reportItem: ClientReportTypeItem, + officeList: List, + loanPurposeList: List, + fundList: List, + currencyList: List, + parCalculatorList: List, + savingsAccountDepositList: List, + glAccountList: List, + obligationDateList: List, + reportOffices: List, + reportProducts: List, + runReportDetail: MutableMap +) { + + var selectedOffice by rememberSaveable { mutableStateOf(officeList.first().row[1]) } + var selectedLoanPurpose by rememberSaveable { mutableStateOf("") } + var selectedLoanOfficer by rememberSaveable { mutableStateOf(reportOffices.first().row[1]) } + var selectedProducts by rememberSaveable { mutableStateOf("") } + var selectedFund by rememberSaveable { mutableStateOf("") } + var selectedCurrency by rememberSaveable { mutableStateOf("") } + var selectedParCalculator by rememberSaveable { mutableStateOf("") } + var selectedSavingsAccountDeposit by rememberSaveable { mutableStateOf("") } + var selectedGlAccount by rememberSaveable { mutableStateOf("") } + var selectedObligationDate by rememberSaveable { mutableStateOf("") } + + var selectedOfficeId by rememberSaveable { mutableStateOf(officeList.first().row.first()) } + var selectedLoanPurposeId by rememberSaveable { mutableStateOf("") } + var selectedLoanOfficerId by rememberSaveable { mutableStateOf(reportOffices.first().row.first()) } + var selectedProductsId by rememberSaveable { mutableStateOf("") } + var selectedFundId by rememberSaveable { mutableStateOf("") } + var selectedCurrencyId by rememberSaveable { mutableStateOf("") } + var selectedParCalculatorId by rememberSaveable { mutableStateOf("") } + var selectedSavingsAccountDepositId by rememberSaveable { mutableStateOf("") } + var selectedGlAccountId by rememberSaveable { mutableStateOf("") } + var selectedObligationDateId by rememberSaveable { mutableStateOf("") } + + LaunchedEffect( + selectedOffice, + selectedLoanPurpose, + selectedLoanOfficer, + selectedProducts, + selectedFund, + selectedCurrency, + selectedParCalculator, + selectedSavingsAccountDeposit, + selectedGlAccount, + selectedObligationDate + ) { + + if (selectedOffice.isNotEmpty()) { + runReportDetail[Constants.R_OFFICE_ID] = selectedOfficeId + } + + if (selectedLoanPurpose.isNotEmpty()) { + runReportDetail[Constants.R_LOAN_PURPOSE_ID] = selectedLoanPurposeId + } + + if (selectedLoanOfficer.isNotEmpty()) { + runReportDetail[Constants.R_LOAN_OFFICER_ID] = selectedLoanOfficerId + } + + if (selectedProducts.isNotEmpty()) { + runReportDetail[Constants.R_LOAN_PRODUCT_ID] = selectedProductsId + } + + if (selectedFund.isNotEmpty()) { + runReportDetail[Constants.R_FUND_ID] = selectedFundId + } + + if (selectedCurrency.isNotEmpty()) { + runReportDetail[Constants.R_CURRENCY_ID] = selectedCurrencyId + } + + if (selectedParCalculator.isNotEmpty()) { + runReportDetail[Constants.R_PAR_TYPE] = selectedParCalculatorId + } + + if (selectedSavingsAccountDeposit.isNotEmpty()) { + runReportDetail[Constants.R_SUB_STATUS] = + selectedSavingsAccountDepositId + } + + if (selectedGlAccount.isNotEmpty()) { + runReportDetail[Constants.R_ACCOUNT] = selectedGlAccountId + } + + if (selectedObligationDate.isNotEmpty()) { + runReportDetail[Constants.R_OBLIG_DATE_TYPE] = selectedObligationDateId + } + + } + + OutlinedCard( + modifier = Modifier + .padding(8.dp), + colors = CardDefaults.cardColors(White) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding( + 16.dp + ), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .size(42.dp) + .background(BlueSecondary, CircleShape), + ) { + Icon( + painter = painterResource(id = R.drawable.feature_report_ic_report_item), + contentDescription = null, + tint = Black + ) + } + Column( + modifier = Modifier + .weight(1f) + .padding(start = 16.dp) + ) { + reportItem.report_name?.let { + Text( + text = it, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + color = Black + ) + ) + } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = reportItem.report_type.toString(), + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + color = DarkGray + ) + ) + Text( + text = reportItem.report_category.toString(), + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + color = DarkGray + ) + ) + } + } + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + if (officeList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedOffice, + onValueChanged = { + selectedOffice = it + }, + onOptionSelected = { index, value -> + selectedOffice = value + selectedOfficeId = officeList[index].row.first() + }, + label = R.string.feature_report_office, + options = officeList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (loanPurposeList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedLoanPurpose, + onValueChanged = { + selectedLoanPurpose = it + }, + onOptionSelected = { index, value -> + selectedLoanPurpose = value + selectedLoanPurposeId = loanPurposeList[index].row.first() + }, + label = R.string.feature_report_loan_purpose, + options = loanPurposeList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (reportOffices.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedLoanOfficer, + onValueChanged = { + selectedLoanOfficer = it + }, + onOptionSelected = { index, value -> + selectedLoanOfficer = value + selectedLoanOfficerId = reportOffices[index].row.first() + }, + label = R.string.feature_report_loan_officer, + options = reportOffices.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (reportProducts.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedProducts, + onValueChanged = { + selectedProducts = it + }, + onOptionSelected = { index, value -> + selectedProducts = value + selectedProductsId = reportProducts[index].row.first() + }, + label = R.string.feature_report_product, + options = reportProducts.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (fundList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedFund, + onValueChanged = { + selectedFund = it + }, + onOptionSelected = { index, value -> + selectedFund = value + selectedFundId = fundList[index].row.first() + }, + label = R.string.feature_report_fund, + options = fundList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (currencyList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedCurrency, + onValueChanged = { + selectedCurrency = it + }, + onOptionSelected = { index, value -> + selectedCurrency = value + selectedCurrencyId = currencyList[index].row.first() + }, + label = R.string.feature_report_currency, + options = currencyList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (parCalculatorList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedParCalculator, + onValueChanged = { + selectedParCalculator = it + }, + onOptionSelected = { index, value -> + selectedParCalculator = value + selectedParCalculatorId = parCalculatorList[index].row.first() + }, + label = R.string.feature_report_par_type, + options = parCalculatorList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (savingsAccountDepositList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedSavingsAccountDeposit, + onValueChanged = { + selectedSavingsAccountDeposit = it + }, + onOptionSelected = { index, value -> + selectedSavingsAccountDeposit = value + selectedSavingsAccountDepositId = savingsAccountDepositList[index].row.first() + }, + label = R.string.feature_report_saving_account, + options = savingsAccountDepositList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (glAccountList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedGlAccount, + onValueChanged = { + selectedGlAccount = it + }, + onOptionSelected = { index, value -> + selectedGlAccount = value + selectedGlAccountId = glAccountList[index].row.first() + }, + label = R.string.feature_report_gl_account, + options = glAccountList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + if (obligationDateList.isNotEmpty()) { + MifosTextFieldDropdown( + value = selectedObligationDate, + onValueChanged = { + selectedObligationDate = it + }, + onOptionSelected = { index, value -> + selectedObligationDate = value + selectedObligationDateId = obligationDateList[index].row.first() + }, + label = R.string.feature_report_obligation_date, + options = obligationDateList.map { it.row[1] }, + readOnly = true + ) + Spacer(modifier = Modifier.height(16.dp)) + } +} + + +class ReportDetailUiStateProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + ReportDetailUiState.Error(R.string.feature_report_failed_to_load_report_details), + ReportDetailUiState.Loading, + ReportDetailUiState.ParameterDetailsSuccess + ) + +} + + +@Preview(showBackground = true) +@Composable +private fun ReportDetailScreenPreview( + @PreviewParameter(ReportDetailUiStateProvider::class) state: ReportDetailUiState +) { + ReportDetailScreen( + reportItem = ClientReportTypeItem(), + state = state, + onBackPressed = {}, + onRetry = {}, + officeList = emptyList(), + loanPurposeList = emptyList(), + fundList = emptyList(), + currencyList = emptyList(), + parCalculatorList = emptyList(), + savingsAccountDepositList = emptyList(), + glAccountList = emptyList(), + obligationDateList = emptyList(), + reportOffices = emptyList(), + reportProducts = emptyList(), + runReport = {} + ) +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailUiState.kt b/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailUiState.kt new file mode 100644 index 00000000000..d3b5311d981 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailUiState.kt @@ -0,0 +1,13 @@ +package com.mifos.feature.report.report_detail + +/** + * Created by Aditya Gupta on 12/08/23. + */ +sealed class ReportDetailUiState { + + data object Loading : ReportDetailUiState() + + data class Error(val message: Int) : ReportDetailUiState() + + data object ParameterDetailsSuccess : ReportDetailUiState() +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailViewModel.kt b/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailViewModel.kt new file mode 100644 index 00000000000..69eae542606 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/report_detail/ReportDetailViewModel.kt @@ -0,0 +1,127 @@ +package com.mifos.feature.report.report_detail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mifos.core.common.utils.Resource +import com.mifos.core.domain.use_cases.GetReportFullParameterListUseCase +import com.mifos.core.domain.use_cases.GetReportParameterDetailsUseCase +import com.mifos.core.domain.use_cases.GetRunReportOfficesUseCase +import com.mifos.core.domain.use_cases.GetRunReportProductUseCase +import com.mifos.core.domain.use_cases.GetRunReportWithQueryUseCase +import com.mifos.core.objects.runreports.DataRow +import com.mifos.core.objects.runreports.FullParameterListResponse +import com.mifos.feature.report.R +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ReportDetailViewModel @Inject constructor( + private val getReportFullParameterListUseCase: GetReportFullParameterListUseCase, + private val getReportParameterDetailsUseCase: GetReportParameterDetailsUseCase, + private val getRunReportProductUseCase: GetRunReportProductUseCase, + private val getRunReportWithQueryUseCase: GetRunReportWithQueryUseCase, + private val getRunReportOfficesUseCase: GetRunReportOfficesUseCase +) : ViewModel() { + + private val _reportDetailUiState = + MutableStateFlow(ReportDetailUiState.Loading) + val reportDetailUiState = _reportDetailUiState.asStateFlow() + + private val _reportParameterList = MutableStateFlow>(emptyList()) + val reportParameterList = _reportParameterList.asStateFlow() + + private val _reportDetail = MutableStateFlow, String>>(Pair(emptyList(), "")) + val reportDetail = _reportDetail.asStateFlow() + + private val _reportOffices = MutableStateFlow>(emptyList()) + val reportOffices = _reportOffices.asStateFlow() + + private val _reportProducts = MutableStateFlow>(emptyList()) + val reportProducts = _reportProducts.asStateFlow() + + private val _runReport = MutableStateFlow(null) + val runReport = _runReport.asStateFlow() + + fun fetchFullParameterList(reportName: String, parameterType: Boolean) = + viewModelScope.launch(Dispatchers.IO) { + getReportFullParameterListUseCase(reportName, parameterType).collect { result -> + when (result) { + is Resource.Error -> _reportDetailUiState.value = + ReportDetailUiState.Error(R.string.feature_report_failed_to_load_report_details) + + is Resource.Loading -> _reportDetailUiState.value = ReportDetailUiState.Loading + + is Resource.Success -> _reportParameterList.value = + result.data?.data ?: emptyList() + } + } + } + + fun fetchParameterDetails(parameterName: String, parameterType: Boolean) = + viewModelScope.launch(Dispatchers.IO) { + getReportParameterDetailsUseCase(parameterName, parameterType).collect { result -> + when (result) { + is Resource.Error -> Unit + + is Resource.Loading -> Unit + + is Resource.Success -> { + _reportDetail.value = + Pair(result.data?.data ?: emptyList(), parameterName) + } + } + } + } + + fun fetchOffices(parameterName: String, officeId: Int, parameterType: Boolean) = + viewModelScope.launch(Dispatchers.IO) { + getRunReportOfficesUseCase(parameterName, officeId, parameterType).collect { result -> + when (result) { + is Resource.Error -> _reportDetailUiState.value = + ReportDetailUiState.Error(R.string.feature_report_failed_to_load_report_details) + + is Resource.Loading -> Unit + + is Resource.Success -> { + _reportOffices.value = result.data?.data ?: emptyList() + _reportDetailUiState.value = ReportDetailUiState.ParameterDetailsSuccess + } + } + } + } + + fun fetchProduct(parameterName: String, currencyId: String, parameterType: Boolean) = + viewModelScope.launch(Dispatchers.IO) { + getRunReportProductUseCase(parameterName, currencyId, parameterType).collect { result -> + when (result) { + is Resource.Error -> _reportDetailUiState.value = + ReportDetailUiState.Error(R.string.feature_report_failed_to_load_report_details) + + is Resource.Loading -> Unit + + is Resource.Success -> { + _reportProducts.value = result.data?.data ?: emptyList() + _reportDetailUiState.value = ReportDetailUiState.ParameterDetailsSuccess + } + } + } + } + + fun fetchRunReportWithQuery(reportName: String, options: MutableMap) = + viewModelScope.launch(Dispatchers.IO) { + getRunReportWithQueryUseCase(reportName, options).collect { result -> + when (result) { + is Resource.Error -> _reportDetailUiState.value = + ReportDetailUiState.Error(R.string.feature_report_failed_to_load_report_details) + + is Resource.Loading -> _reportDetailUiState.value = ReportDetailUiState.Loading + + is Resource.Success -> _runReport.value = result.data + } + } + } +} \ No newline at end of file diff --git a/feature/report/src/main/res/values/strings.xml b/feature/report/src/main/res/values/strings.xml index 513ff719e0c..e58a16eaa40 100644 --- a/feature/report/src/main/res/values/strings.xml +++ b/feature/report/src/main/res/values/strings.xml @@ -12,4 +12,31 @@ No Reports Found + Report Details + Loan Officer + Office + Product + Loan Purpose + Currency + Par type + Saving Account + GL Account + Obligation Date + Failed to Load Report Details + Run Report + + Report + Export CSV + /mifos/documents/report/ + + Permissions Required + You need to approve these permissions in order to Save. + Proceed + Dismiss + + Unable to create directory + Unable to Export + Exported Successfully + Export Started + \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/module/RepositoryModule.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/module/RepositoryModule.kt index 22ecfd89406..2b2dc867cfb 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/module/RepositoryModule.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/injection/module/RepositoryModule.kt @@ -14,7 +14,6 @@ import com.mifos.core.network.datamanager.DataManagerGroups import com.mifos.core.network.datamanager.DataManagerLoan import com.mifos.core.network.datamanager.DataManagerNote import com.mifos.core.network.datamanager.DataManagerOffices -import com.mifos.core.network.datamanager.DataManagerRunReport import com.mifos.core.network.datamanager.DataManagerSavings import com.mifos.core.network.datamanager.DataManagerSearch import com.mifos.core.network.datamanager.DataManagerStaff @@ -103,8 +102,6 @@ import com.mifos.mifosxdroid.online.loanrepaymentschedule.LoanRepaymentScheduleR import com.mifos.mifosxdroid.online.loanrepaymentschedule.LoanRepaymentScheduleRepositoryImp import com.mifos.mifosxdroid.online.loantransactions.LoanTransactionsRepository import com.mifos.mifosxdroid.online.loantransactions.LoanTransactionsRepositoryImp -import com.mifos.mifosxdroid.online.runreports.reportdetail.ReportDetailRepository -import com.mifos.mifosxdroid.online.runreports.reportdetail.ReportDetailRepositoryImp import com.mifos.mifosxdroid.online.savingaccountsummary.SavingsAccountSummaryRepository import com.mifos.mifosxdroid.online.savingaccountsummary.SavingsAccountSummaryRepositoryImp import com.mifos.mifosxdroid.online.savingaccounttransaction.SavingsAccountTransactionRepository @@ -308,11 +305,6 @@ class RepositoryModule { return GroupLoanAccountRepositoryImp(dataManager) } - @Provides - fun providesReportDetailRepository(dataManager: DataManagerRunReport): ReportDetailRepository { - return ReportDetailRepositoryImp(dataManager) - } - @Provides fun providesLoanRepaymentScheduleRepository(dataManager: DataManager): LoanRepaymentScheduleRepository { return LoanRepaymentScheduleRepositoryImp(dataManager) diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/RunReportsActivity.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/RunReportsActivity.kt index 1bb819ec90d..d7dfea23d12 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/RunReportsActivity.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/RunReportsActivity.kt @@ -1,47 +1,20 @@ package com.mifos.mifosxdroid.online.runreports -import android.content.Intent import android.os.Bundle -import android.view.View -import android.widget.AdapterView -import android.widget.AdapterView.OnItemSelectedListener -import android.widget.ArrayAdapter -import android.widget.Spinner -import androidx.appcompat.widget.Toolbar -import androidx.fragment.app.FragmentManager import androidx.navigation.fragment.NavHostFragment -import com.mifos.core.common.utils.Constants import com.mifos.mifosxdroid.R import com.mifos.mifosxdroid.core.MifosBaseActivity -import com.mifos.mifosxdroid.online.runreports.report.ReportFragment -import com.mifos.mifosxdroid.online.runreports.reportcategory.ReportCategoryFragment -import com.mifos.mifosxdroid.online.runreports.reportdetail.ReportDetailFragment import dagger.hilt.android.AndroidEntryPoint /** * Created by Tarun on 02-08-17. */ @AndroidEntryPoint -class RunReportsActivity : MifosBaseActivity(), OnItemSelectedListener { - private var intent: Intent? = null - private var spinner: Spinner? = null +class RunReportsActivity : MifosBaseActivity() { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_toolbar_container) - val toolbar = findViewById(R.id.toolbar) - setSupportActionBar(toolbar) - supportActionBar?.setDisplayShowTitleEnabled(false) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - spinner = Spinner(supportActionBar?.themedContext) - val adapter = ArrayAdapter.createFromResource( - this, - R.array.array_runreport, R.layout.simple_spinner_item - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner?.adapter = adapter - spinner?.onItemSelectedListener = this - toolbar.addView(spinner) - intent = Intent(Constants.ACTION_REPORT) val navHostFragment = supportFragmentManager.findFragmentById(R.id.container_nav_host_fragment) as NavHostFragment navHostFragment.navController.apply { @@ -49,93 +22,4 @@ class RunReportsActivity : MifosBaseActivity(), OnItemSelectedListener { navigate(R.id.reportCategoryFragment) } } - - override fun onItemSelected(adapterView: AdapterView<*>?, view: View, i: Int, l: Long) { - when (i) { - 0 -> { - intent?.putExtra(Constants.REPORT_CATEGORY, Constants.CLIENT) - sendBroadcast(intent) - } - - 1 -> { - intent?.putExtra(Constants.REPORT_CATEGORY, Constants.LOAN) - sendBroadcast(intent) - } - - 2 -> { - intent?.putExtra(Constants.REPORT_CATEGORY, Constants.SAVINGS) - sendBroadcast(intent) - } - - 3 -> { - intent?.putExtra(Constants.REPORT_CATEGORY, Constants.FUND) - sendBroadcast(intent) - } - - 4 -> { - intent?.putExtra(Constants.REPORT_CATEGORY, Constants.ACCOUNTING) - sendBroadcast(intent) - } - - 5 -> {} - } - } - - override fun onNothingSelected(adapterView: AdapterView<*>?) {} - private fun addOnBackStackChangedListener() { - supportFragmentManager.addOnBackStackChangedListener { - val fragmentManager = supportFragmentManager - val fragment = fragmentManager.findFragmentById(R.id.container) - if (fragment is ReportDetailFragment) { - spinner?.visibility = View.INVISIBLE - } else if (fragment is ReportFragment) { - spinner?.visibility = View.INVISIBLE - spinner?.onItemSelectedListener = object : OnItemSelectedListener { - override fun onItemSelected( - adapterView: AdapterView<*>?, - view: View, i: Int, l: Long - ) { - when (i) { - 0 -> sendBroadcastFromReportFragment( - fragmentManager, Constants.CLIENT - ) - - 1 -> sendBroadcastFromReportFragment( - fragmentManager, Constants.LOAN - ) - - 2 -> sendBroadcastFromReportFragment( - fragmentManager, Constants.SAVINGS - ) - - 3 -> sendBroadcastFromReportFragment( - fragmentManager, Constants.FUND - ) - - 4 -> sendBroadcastFromReportFragment( - fragmentManager, Constants.ACCOUNTING - ) - - 5 -> {} - } - } - - override fun onNothingSelected(adapterView: AdapterView<*>?) {} - } - } else if (fragment is ReportCategoryFragment) { - spinner?.visibility = View.INVISIBLE - } - } - } - - private fun sendBroadcastFromReportFragment( - fragmentManager: FragmentManager, - reportCategory: String - ) { - fragmentManager.popBackStack() - fragmentManager.popBackStack() - fragmentManager.executePendingTransactions() - intent?.putExtra(Constants.REPORT_CATEGORY, reportCategory) - sendBroadcast(intent) - } } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/report/ReportFragment.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/report/ReportFragment.kt index fe2508e6a93..46ce12e8c94 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/report/ReportFragment.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/report/ReportFragment.kt @@ -1,275 +1,49 @@ package com.mifos.mifosxdroid.online.runreports.report -import android.Manifest -import android.content.pm.PackageManager -import android.graphics.Typeface -import android.os.AsyncTask -import android.os.Build import android.os.Bundle -import android.os.Environment -import android.text.TextUtils -import android.view.Gravity import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.widget.TableRow -import android.widget.TextView -import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.ui.platform.ComposeView +import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import com.mifos.core.common.utils.Constants import com.mifos.core.objects.runreports.FullParameterListResponse -import com.mifos.mifosxdroid.R -import com.mifos.mifosxdroid.core.MifosBaseActivity +import com.mifos.feature.report.report.ReportScreen import com.mifos.mifosxdroid.core.MifosBaseFragment -import com.mifos.mifosxdroid.core.util.Toaster.show -import com.mifos.mifosxdroid.databinding.FragmentClientReportBinding -import com.mifos.mifosxdroid.views.scrollview.ScrollChangeListener -import com.mifos.utils.CheckSelfPermissionAndRequest import dagger.hilt.android.AndroidEntryPoint -import java.io.File -import java.io.FileWriter -import java.io.IOException -import java.util.Date /** * Created by Tarun on 05-08-17. */ @AndroidEntryPoint -class ReportFragment : MifosBaseFragment(), ScrollChangeListener { +class ReportFragment : MifosBaseFragment() { - private lateinit var binding: FragmentClientReportBinding private val arg: ReportFragmentArgs by navArgs() - private var report: FullParameterListResponse? = null - private var page = 0 - private var bottom = 0 + private lateinit var report: FullParameterListResponse override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = FragmentClientReportBinding.inflate(inflater, container, false) - setHasOptionsMenu(true) - val time = Date().time report = arg.respose - setUpUi() - return binding.root - } - - private fun setUpUi() { - showProgressbar(true) - setUpHeading() - binding.svHorizontal.setScrollChangeListener(this) - report?.data?.let { data -> - if (data.isNotEmpty()) { - setUpValues() - } else { - Toast.makeText(activity, getString(R.string.msg_report_empty), Toast.LENGTH_SHORT) - .show() - } - } - showProgressbar(false) - } - - private fun setUpHeading() { - val row = TableRow(context) - val headingRowParams = TableRow.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT - ) - headingRowParams.gravity = Gravity.CENTER - headingRowParams.setMargins(0, 0, 0, 10) - row.layoutParams = headingRowParams - for (column in report?.columnHeaders ?: emptyList()) { - when (column.columnDisplayType) { - "STRING" -> { - val tv = TextView(context) - tv.setTypeface(tv.typeface, Typeface.BOLD) - tv.gravity = Gravity.CENTER - tv.text = column.columnName - row.addView(tv) - } + return ComposeView(requireContext()).apply { + setContent { + ReportScreen(report = report, onBackPressed = { + findNavController().popBackStack() + }) } } - binding.tableReport.addView(row) } - private fun setUpValues() { - val ll = page * 100 - val ul = report?.data?.size?.let { Math.min(ll + 100, it) } - for (dataRow in ul?.let { report?.data?.subList(ll, it) } ?: emptyList()) { - val row = TableRow(context) - val rowParams = TableRow.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT - ) - rowParams.gravity = Gravity.CENTER - rowParams.setMargins(0, 0, 0, 10) - row.layoutParams = rowParams - for (i in report?.columnHeaders?.indices ?: emptyList()) { - when (report?.columnHeaders?.get(i)?.columnDisplayType) { - "STRING" -> { - val tv = TextView(context) - tv.gravity = Gravity.CENTER - tv.text = dataRow.row.getOrNull(i) ?: "-" - row.addView(tv) - } - } - } - binding.tableReport.addView(row) - } - } - - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_report, menu) - super.onCreateOptionsMenu(menu, inflater) + override fun onResume() { + super.onResume() + (requireActivity() as AppCompatActivity).supportActionBar?.hide() } - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.item_download_report -> { - checkPermissionAndExport() - return true - } - } - return super.onOptionsItemSelected(item) - } - - fun checkPermissionAndExport() { - if (CheckSelfPermissionAndRequest.checkSelfPermission( - activity, - Manifest.permission.WRITE_EXTERNAL_STORAGE - ) - ) { - val exportCsvAsyncTask = ExportCsvAsyncTask() - exportCsvAsyncTask.execute(report) - } else { - requestPermission() - } - } - - fun requestPermission() { - CheckSelfPermissionAndRequest.requestPermission( - activity as MifosBaseActivity, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Constants.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE, - resources.getString( - R.string.dialog_message_write_external_storage_permission_denied - ), - resources.getString(R.string.dialog_message_permission_never_ask_again_write), - Constants.WRITE_EXTERNAL_STORAGE_STATUS - ) - } - - override fun onRequestPermissionsResult( - requestCode: Int, permissions: Array, - grantResults: IntArray - ) { - if (requestCode == Constants.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE) { - if (grantResults.isNotEmpty() - && grantResults[0] == PackageManager.PERMISSION_GRANTED - ) { - val exportCsvAsyncTask = ExportCsvAsyncTask() - exportCsvAsyncTask.execute(report) - } else { - show( - binding.root, resources - .getString(R.string.permission_denied_to_write_external_document) - ) - } - } - } - - internal open inner class ExportCsvAsyncTask : - AsyncTask() { - var reportDirectoryPath: String? = null - lateinit var reportPath: String - var reportDirectory: File? = null - var fileWriter: FileWriter? = null - var report: FullParameterListResponse? = null - override fun onPreExecute() { - super.onPreExecute() - showProgressbar(true) - reportDirectoryPath = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) - .toString() + - getString(R.string.export_csv_directory) - val timestamp = System.currentTimeMillis() - reportPath = "$reportDirectoryPath$timestamp.csv" - reportDirectory = File(reportDirectoryPath) - } - - override fun doInBackground(vararg p0: FullParameterListResponse?): String? { - if (reportDirectory?.exists() != true) { - val makeRequiredDirectories = reportDirectory?.mkdirs() - if (makeRequiredDirectories != true) { - return "Directory Creation Failed" - } - } - - report = p0[0] - try { - fileWriter = FileWriter(reportPath) - - // write headers - val columnSize = report?.columnHeaders?.size - var count = 1 - for (header in report?.columnHeaders ?: emptyList()) { - fileWriter?.append(header.columnName) - if (count == columnSize) { - fileWriter?.append("\n") - } else { - fileWriter?.append(",") - } - count++ - } - - // write row data - for (row in report?.data!!) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - fileWriter?.append(java.lang.String.join(",", row.row)) - } else { - fileWriter?.append(TextUtils.join(",", row.row)) - } - fileWriter?.append("\n") - } - fileWriter?.flush() - fileWriter?.close() - } catch (e: IOException) { - return "File Creation Failed" - } - return "Saved at $reportPath" - } - - override fun onPostExecute(result: String) { - super.onPostExecute(result) - showProgressbar(false) - Toast.makeText(context, result, Toast.LENGTH_LONG).show() - } - } - - private fun showProgressbar(b: Boolean) { - if (b) { - showMifosProgressDialog() - } else { - hideMifosProgressDialog() - } - } - - override fun onScrollChanged(x: Int, y: Int, oldx: Int, oldy: Int) { - val view = binding.svHorizontal.getChildAt(binding.svHorizontal.childCount - 1) - val diff = view.bottom - (binding.svHorizontal.height + binding.svHorizontal.scrollY) - if (diff == 0) { - if (bottom >= 2) { - bottom = 0 - page++ - Toast.makeText(context, "Loading more", Toast.LENGTH_SHORT).show() - setUpValues() - } else { - bottom++ - } - } + override fun onStop() { + super.onStop() + (requireActivity() as AppCompatActivity).supportActionBar?.show() } } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailFragment.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailFragment.kt index 2077c566a8d..6c6c431d614 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailFragment.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailFragment.kt @@ -1,519 +1,64 @@ package com.mifos.mifosxdroid.online.runreports.reportdetail import android.os.Bundle -import android.view.Gravity import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.widget.AdapterView -import android.widget.AdapterView.OnItemSelectedListener -import android.widget.ArrayAdapter -import android.widget.EditText -import android.widget.Spinner -import android.widget.TableRow -import android.widget.TextView -import androidx.fragment.app.DialogFragment -import androidx.lifecycle.ViewModelProvider +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import com.mifos.core.common.utils.Constants import com.mifos.core.objects.runreports.FullParameterListResponse import com.mifos.core.objects.runreports.client.ClientReportTypeItem -import com.mifos.mifosxdroid.R +import com.mifos.feature.report.report_detail.ReportDetailScreen import com.mifos.mifosxdroid.core.MifosBaseFragment -import com.mifos.mifosxdroid.core.util.Toaster.show -import com.mifos.mifosxdroid.databinding.FragmentClientReportDetailsBinding -import com.mifos.mifosxdroid.uihelpers.MFDatePicker -import com.mifos.mifosxdroid.uihelpers.MFDatePicker.OnDatePickListener -import com.mifos.utils.FragmentConstants import dagger.hilt.android.AndroidEntryPoint -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.Date /** * Created by Tarun on 04-08-17. */ @AndroidEntryPoint -class ReportDetailFragment : MifosBaseFragment(), OnDatePickListener { +class ReportDetailFragment : MifosBaseFragment() { - private lateinit var binding: FragmentClientReportDetailsBinding private val arg: ReportDetailFragmentArgs by navArgs() - - private lateinit var viewModel: ReportDetailViewModel - - private var reportItem: ClientReportTypeItem? = null - private var fetchLoanOfficer = false - private var fetchLoanProduct = false - private var fundMap: HashMap? = null - private var loanOfficerMap: HashMap? = null - private var loanProductMap: HashMap? = null - private var loanPurposeMap: HashMap? = null - private var officeMap: HashMap? = null - private var parMap: HashMap? = null - private var subStatusMap: HashMap? = null - private var glAccountNoMap: HashMap? = null - private var obligDateTypeMap: HashMap? = null - private var currencyMap: HashMap? = null - private var dateField: String? = null - private var datePicker: DialogFragment? = null - private var tvField: EditText? = null + private lateinit var reportItem: ClientReportTypeItem override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = FragmentClientReportDetailsBinding.inflate(inflater, container, false) - setHasOptionsMenu(true) - viewModel = ViewModelProvider(this)[ReportDetailViewModel::class.java] reportItem = arg.clientReportTypeItem - setUpUi() - - viewModel.reportDetailUiState.observe(viewLifecycleOwner) { - when (it) { - is ReportDetailUiState.ShowError -> { - showProgressbar(false) - showError(it.message) - } - - is ReportDetailUiState.ShowFullParameterResponse -> { - showProgressbar(false) - showFullParameterResponse(it.response) - } - - is ReportDetailUiState.ShowOffices -> { - showProgressbar(false) - showOffices(it.response, it.parameterName) - } - - is ReportDetailUiState.ShowParameterDetails -> { - showProgressbar(false) - showParameterDetails(it.response, it.parameterName) - } - - is ReportDetailUiState.ShowProduct -> { - showProgressbar(false) - showProduct(it.response, it.parameterName) - } - - is ReportDetailUiState.ShowProgressbar -> showProgressbar(true) - is ReportDetailUiState.ShowRunReport -> { - showProgressbar(false) - showRunReport(it.response) - } + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + ReportDetailScreen( + reportItem = reportItem, + onBackPressed = { + findNavController().popBackStack() + }, + runReport = { + showRunReport(it) + } + ) } } - - return binding.root } - private fun setUpUi() { - binding.itemClient.tvReportName.text = reportItem?.report_name - binding.itemClient.tvReportCategory.text = reportItem?.report_category - binding.itemClient.tvReportType.text = reportItem?.report_type - val reportName = "'" + reportItem?.report_name + "'" - viewModel.fetchFullParameterList(reportName, true) - datePicker = MFDatePicker.newInsance(this) + override fun onResume() { + super.onResume() + (requireActivity() as AppCompatActivity).supportActionBar?.hide() } - private fun addTableRow(data: FullParameterListResponse, identifier: String) { - val row = TableRow(context) - val rowParams = TableRow.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT - ) - rowParams.gravity = Gravity.CENTER - rowParams.setMargins(0, 0, 0, 10) - row.layoutParams = rowParams - val tvLabel = TextView(context) - row.addView(tvLabel) - val spinner = Spinner(context) - row.addView(spinner) - val spinnerValues = ArrayList() - when (identifier) { - Constants.LOAN_OFFICER_ID_SELECT -> { - spinner.tag = Constants.R_LOAN_OFFICER_ID - loanOfficerMap = viewModel.filterIntHashMapForSpinner( - data.data, - spinnerValues - ) - tvLabel.text = getString(R.string.loan_officer) - } - - Constants.LOAN_PRODUCT_ID_SELECT -> { - spinner.tag = Constants.R_LOAN_PRODUCT_ID - loanProductMap = viewModel.filterIntHashMapForSpinner( - data.data, - spinnerValues - ) - tvLabel.text = getString(R.string.loanproduct) - } - - Constants.LOAN_PURPOSE_ID_SELECT -> { - spinner.tag = Constants.R_LOAN_PURPOSE_ID - loanPurposeMap = viewModel.filterIntHashMapForSpinner( - data.data, - spinnerValues - ) - tvLabel.text = getString(R.string.report_loan_purpose) - } - - Constants.FUND_ID_SELECT -> { - spinner.tag = Constants.R_FUND_ID - fundMap = viewModel.filterIntHashMapForSpinner(data.data, spinnerValues) - tvLabel.text = getString(R.string.loan_fund) - } - - Constants.CURRENCY_ID_SELECT -> { - spinner.tag = Constants.R_CURRENCY_ID - currencyMap = viewModel.filterStringHashMapForSpinner( - data.data, - spinnerValues - ) - tvLabel.text = getString(R.string.currency) - } - - Constants.OFFICE_ID_SELECT -> { - spinner.tag = Constants.R_OFFICE_ID - officeMap = viewModel.filterIntHashMapForSpinner(data.data, spinnerValues) - tvLabel.text = getString(R.string.office) - } - - Constants.PAR_TYPE_SELECT -> { - spinner.tag = Constants.R_PAR_TYPE - parMap = viewModel.filterIntHashMapForSpinner(data.data, spinnerValues) - tvLabel.text = getString(R.string.par_calculation) - } - - Constants.SAVINGS_ACCOUNT_SUB_STATUS -> { - spinner.tag = Constants.R_SUB_STATUS - subStatusMap = viewModel.filterIntHashMapForSpinner(data.data, spinnerValues) - tvLabel.text = getString(R.string.savings_acc_deposit) - } - - Constants.SELECT_GL_ACCOUNT_NO -> { - spinner.tag = Constants.R_ACCOUNT - glAccountNoMap = viewModel.filterIntHashMapForSpinner(data.data, spinnerValues) - tvLabel.text = getString(R.string.glaccount) - } - - Constants.OBLIG_DATE_TYPE_SELECT -> { - spinner.tag = Constants.R_OBLIG_DATE_TYPE - obligDateTypeMap = viewModel.filterIntHashMapForSpinner(data.data, spinnerValues) - tvLabel.text = getString(R.string.obligation_date_type) - } - } - val adapter: ArrayAdapter<*> = ArrayAdapter( - requireActivity(), - android.R.layout.simple_spinner_item, spinnerValues - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = adapter - spinner.onItemSelectedListener = object : OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View, - position: Int, - id: Long - ) { - if (spinner.tag.toString() == Constants.R_OFFICE_ID && fetchLoanOfficer) { - val officeId = officeMap!![spinner.selectedItem.toString()]!! - viewModel.fetchOffices(Constants.LOAN_OFFICER_ID_SELECT, officeId, true) - } else if (spinner.tag.toString() == Constants.R_CURRENCY_ID && fetchLoanProduct) { - val currencyId = currencyMap!![spinner.selectedItem.toString()] - viewModel.fetchProduct(Constants.LOAN_PRODUCT_ID_SELECT, currencyId, true) - } - } - - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - binding.tableDetails.addView(row) + override fun onStop() { + super.onStop() + (requireActivity() as AppCompatActivity).supportActionBar?.show() } - private fun runReport() { - if (binding.tableDetails.childCount < 1) { - show(binding.root, getString(R.string.msg_report_empty)) - } else { - var fundId: Int? - var loanOfficeId: Int? - var loanProductId: Int? - var loanPurposeId: Int? - var officeId: Int? - var parId: Int? - var subId: Int? - var obligId: Int? - var glAccountId: Int? - var currencyId: String? - val map: MutableMap = HashMap() - - /* There are variable number of parameters in the request query. - Hence, create a Map instead of hardcoding the number of - query parameters in the Retrofit Service.*/for (i in 0 until binding.tableDetails.childCount) { - val tableRow = binding.tableDetails.getChildAt(i) as TableRow - if (tableRow.getChildAt(1) is Spinner) { - val sp = tableRow.getChildAt(1) as Spinner - when (sp.tag.toString()) { - Constants.R_LOAN_OFFICER_ID -> { - loanOfficeId = loanOfficerMap!![sp.selectedItem.toString()] - if (loanOfficeId != -1) { - map[sp.tag.toString()] = loanOfficeId.toString() - } - } - - Constants.R_LOAN_PRODUCT_ID -> { - loanProductId = loanProductMap!![sp.selectedItem.toString()] - if (loanProductId != -1) { - map[sp.tag.toString()] = loanProductId.toString() - } - } - - Constants.R_LOAN_PURPOSE_ID -> { - loanPurposeId = loanPurposeMap!![sp.selectedItem.toString()] - if (loanPurposeId != -1) { - map[sp.tag.toString()] = loanPurposeId.toString() - } - } - - Constants.R_FUND_ID -> { - fundId = fundMap!![sp.selectedItem.toString()] - if (fundId != -1) { - map[sp.tag.toString()] = fundId.toString() - } - } - - Constants.R_CURRENCY_ID -> { - currencyId = currencyMap!![sp.selectedItem.toString()] - if (currencyId != "") { - map[sp.tag.toString()] = currencyId - } - } - - Constants.R_OFFICE_ID -> { - officeId = officeMap!![sp.selectedItem.toString()] - if (officeId != -1) { - map[sp.tag.toString()] = officeId.toString() - } - } - - Constants.R_PAR_TYPE -> { - parId = parMap!![sp.selectedItem.toString()] - if (parId != -1) { - map[sp.tag.toString()] = parId.toString() - } - } - - Constants.R_ACCOUNT -> { - glAccountId = glAccountNoMap!![sp.selectedItem.toString()] - if (glAccountId != -1) { - map[sp.tag.toString()] = glAccountId.toString() - } - } - - Constants.R_SUB_STATUS -> { - subId = subStatusMap!![sp.selectedItem.toString()] - if (subId != -1) { - map[sp.tag.toString()] = subId.toString() - } - } - - Constants.R_OBLIG_DATE_TYPE -> { - obligId = obligDateTypeMap!![sp.selectedItem.toString()] - if (obligId != -1) { - map[sp.tag.toString()] = obligId.toString() - } - } - } - } else if (tableRow.getChildAt(1) is EditText) { - val et = tableRow.getChildAt(1) as EditText - map[et.tag.toString()] = et.text.toString() - } - } - viewModel.fetchRunReportWithQuery(reportItem?.report_name, map) - } - } private fun showRunReport(response: FullParameterListResponse) { val action = ReportDetailFragmentDirections.actionReportDetailFragmentToReportFragment(response) findNavController().navigate(action) } - - private fun showOffices(response: FullParameterListResponse, identifier: String) { - for (i in 0 until binding.tableDetails.childCount) { - val tableRow = binding.tableDetails.getChildAt(i) as TableRow - if (tableRow.getChildAt(1) is EditText) { - continue - } - val sp = tableRow.getChildAt(1) as Spinner - if (sp.tag.toString() == Constants.R_LOAN_OFFICER_ID) { - val spinnerValues = ArrayList() - loanOfficerMap = viewModel.filterIntHashMapForSpinner( - response.data, - spinnerValues - ) - val adapter: ArrayAdapter<*> = ArrayAdapter( - requireActivity(), - android.R.layout.simple_spinner_item, spinnerValues - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - sp.adapter = adapter - return - } - } - addTableRow(response, identifier) - } - - private fun showProduct(response: FullParameterListResponse, identifier: String) { - for (i in 0 until binding.tableDetails.childCount) { - val tableRow = binding.tableDetails.getChildAt(i) as TableRow - if (tableRow.getChildAt(1) is EditText) { - continue - } - val sp = tableRow.getChildAt(1) as Spinner - if (sp.tag.toString() == Constants.R_LOAN_PRODUCT_ID) { - val spinnerValues = ArrayList() - loanProductMap = viewModel.filterIntHashMapForSpinner( - response.data, - spinnerValues - ) - val adapter: ArrayAdapter<*> = ArrayAdapter( - requireActivity(), - android.R.layout.simple_spinner_item, spinnerValues - ) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - sp.adapter = adapter - return - } - } - addTableRow(response, identifier) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_runreport, menu) - super.onCreateOptionsMenu(menu, inflater) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.item_run_report -> runReport() - } - return super.onOptionsItemSelected(item) - } - - private fun showError(error: String) { - show(binding.root, error) - } - - private fun showFullParameterResponse(response: FullParameterListResponse) { - for (row in response.data) { - when (row.row[0]) { - Constants.LOAN_OFFICER_ID_SELECT -> fetchLoanOfficer = true - Constants.LOAN_PRODUCT_ID_SELECT -> fetchLoanProduct = true - Constants.START_DATE_SELECT -> addTextView(Constants.START_DATE_SELECT) - Constants.END_DATE_SELECT -> addTextView(Constants.END_DATE_SELECT) - Constants.SELECT_ACCOUNT -> addTextView(Constants.SELECT_ACCOUNT) - Constants.FROM_X_SELECT -> addTextView(Constants.FROM_X_SELECT) - Constants.TO_Y_SELECT -> addTextView(Constants.TO_Y_SELECT) - Constants.OVERDUE_X_SELECT -> addTextView(Constants.OVERDUE_X_SELECT) - Constants.OVERDUE_Y_SELECT -> addTextView(Constants.OVERDUE_Y_SELECT) - } - viewModel.fetchParameterDetails(row.row[0], true) - } - } - - private fun addTextView(identifier: String) { - val row = TableRow(context) - val rowParams = TableRow.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT - ) - rowParams.gravity = Gravity.CENTER - rowParams.setMargins(0, 0, 0, 10) - row.layoutParams = rowParams - val tvLabel = TextView(context) - row.addView(tvLabel) - tvField = EditText(context) - row.addView(tvField) - when (identifier) { - Constants.START_DATE_SELECT -> { - tvField?.tag = Constants.R_START_DATE - tvLabel.text = getString(R.string.start_date) - } - - Constants.END_DATE_SELECT -> { - tvField?.tag = Constants.R_END_DATE - tvLabel.text = getString(R.string.end_date) - } - - Constants.SELECT_ACCOUNT -> { - tvField?.tag = Constants.R_ACCOUNT_NO - tvLabel.text = getString(R.string.enter_account_no) - } - - Constants.FROM_X_SELECT -> { - tvField?.tag = Constants.R_FROM_X - tvLabel.text = getString(R.string.from_x_number) - } - - Constants.TO_Y_SELECT -> { - tvField?.tag = Constants.R_TO_Y - tvLabel.text = getString(R.string.to_y_number) - } - - Constants.OVERDUE_X_SELECT -> { - tvField?.tag = Constants.R_OVERDUE_X - tvLabel.text = getString(R.string.overdue_x_number) - } - - Constants.OVERDUE_Y_SELECT -> { - tvField?.tag = Constants.R_OVERDUE_Y - tvLabel.text = getString(R.string.overdue_y_number) - } - } - tvField?.isFocusable = false - tvField?.setOnClickListener { v -> - dateField = v.tag.toString() - if (dateField == Constants.R_START_DATE || dateField == Constants.R_END_DATE) { - datePicker?.show( - requireActivity().supportFragmentManager, - FragmentConstants.DFRAG_DATE_PICKER - ) - } - } - binding.tableDetails.addView(row) - } - - private fun showParameterDetails(response: FullParameterListResponse, identifier: String) { - addTableRow(response, identifier) - } - - private fun showProgressbar(b: Boolean) { - if (b) { - showMifosProgressDialog() - } else { - hideMifosProgressDialog() - } - } - - override fun onDatePicked(date: String?) { - for (i in 0 until binding.tableDetails.childCount) { - val tableRow = binding.tableDetails.getChildAt(i) as TableRow - if (tableRow.getChildAt(1) is Spinner) { - continue - } - val et = tableRow.getChildAt(1) as EditText - val simpleDateFormat = SimpleDateFormat("dd-MM-yyyy") - var dateModified: Date? = null - try { - dateModified = simpleDateFormat.parse(date) - } catch (e: ParseException) { - } - val simpleDateFormat1 = SimpleDateFormat("yyyy-MM-dd") - if (et.tag.toString() == dateField) { - et.setText(simpleDateFormat1.format(dateModified)) - break - } - } - } } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailRepository.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailRepository.kt deleted file mode 100644 index f2fd7b186cf..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailRepository.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.mifos.mifosxdroid.online.runreports.reportdetail - -import com.mifos.core.objects.runreports.FullParameterListResponse -import rx.Observable - -/** - * Created by Aditya Gupta on 12/08/23. - */ -interface ReportDetailRepository { - - fun getReportFullParameterList( - reportName: String?, parameterType: Boolean - ): Observable - - fun getReportParameterDetails( - parameterName: String?, parameterType: Boolean - ): Observable - - fun getRunReportOffices( - parameterName: String?, officeId: Int, parameterType: Boolean - ): Observable - - fun getRunReportProduct( - parameterName: String?, currency: String?, parameterType: Boolean - ): Observable - - fun getRunReportWithQuery( - reportName: String?, options: Map - ): Observable - -} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailUiState.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailUiState.kt deleted file mode 100644 index 32fce9b973f..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailUiState.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.mifos.mifosxdroid.online.runreports.reportdetail - -import com.mifos.core.objects.runreports.FullParameterListResponse - -/** - * Created by Aditya Gupta on 12/08/23. - */ -sealed class ReportDetailUiState { - - data object ShowProgressbar : ReportDetailUiState() - - data class ShowError(val message: String) : ReportDetailUiState() - - data class ShowFullParameterResponse(val response: FullParameterListResponse) : - ReportDetailUiState() - - data class ShowParameterDetails( - val response: FullParameterListResponse, - val parameterName: String - ) : ReportDetailUiState() - - data class ShowOffices(val response: FullParameterListResponse, val parameterName: String) : - ReportDetailUiState() - - data class ShowProduct(val response: FullParameterListResponse, val parameterName: String) : - ReportDetailUiState() - - data class ShowRunReport(val response: FullParameterListResponse) : ReportDetailUiState() -} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailViewModel.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailViewModel.kt deleted file mode 100644 index 3ad40094eeb..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportdetail/ReportDetailViewModel.kt +++ /dev/null @@ -1,233 +0,0 @@ -package com.mifos.mifosxdroid.online.runreports.reportdetail - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.mifos.core.objects.runreports.DataRow -import com.mifos.core.objects.runreports.FullParameterListResponse -import dagger.hilt.android.lifecycle.HiltViewModel -import retrofit2.HttpException -import rx.Observable -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.plugins.RxJavaPlugins -import rx.schedulers.Schedulers -import javax.inject.Inject - -/** - * Created by Aditya Gupta on 12/08/23. - */ -@HiltViewModel -class ReportDetailViewModel @Inject constructor(private val repository: ReportDetailRepository) : - ViewModel() { - - private val _reportDetailUiState = MutableLiveData() - - val reportDetailUiState: LiveData - get() = _reportDetailUiState - - fun fetchFullParameterList(reportName: String?, parameterType: Boolean) { - _reportDetailUiState.value = ReportDetailUiState.ShowProgressbar - repository.getReportFullParameterList(reportName, parameterType) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - try { - if (e is HttpException) { - val errorMessage = e.response()?.errorBody() - ?.string() - _reportDetailUiState.value = errorMessage?.let { - ReportDetailUiState.ShowError( - it - ) - } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(response: FullParameterListResponse) { - _reportDetailUiState.value = - ReportDetailUiState.ShowFullParameterResponse(response) - } - }) - - } - - fun fetchParameterDetails(parameterName: String?, parameterType: Boolean) { - _reportDetailUiState.value = ReportDetailUiState.ShowProgressbar - repository.getReportParameterDetails(parameterName, parameterType) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - try { - if (e is HttpException) { - val errorMessage = e.response()?.errorBody() - ?.string() - _reportDetailUiState.value = errorMessage?.let { - ReportDetailUiState.ShowError( - it - ) - } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(response: FullParameterListResponse) { - _reportDetailUiState.value = - parameterName?.let { - ReportDetailUiState.ShowParameterDetails( - response, - it - ) - } - } - }) - - } - - fun fetchOffices(parameterName: String?, officeId: Int, parameterType: Boolean) { - _reportDetailUiState.value = ReportDetailUiState.ShowProgressbar - repository.getRunReportOffices(parameterName, officeId, parameterType) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - try { - if (e is HttpException) { - val errorMessage = e.response()?.errorBody() - ?.string() - _reportDetailUiState.value = errorMessage?.let { - ReportDetailUiState.ShowError( - it - ) - } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(response: FullParameterListResponse) { - _reportDetailUiState.value = - parameterName?.let { ReportDetailUiState.ShowOffices(response, it) } - } - }) - - } - - fun fetchProduct(parameterName: String?, currencyId: String?, parameterType: Boolean) { - _reportDetailUiState.value = ReportDetailUiState.ShowProgressbar - repository.getRunReportProduct(parameterName, currencyId, parameterType) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - try { - if (e is HttpException) { - val errorMessage = e.response()?.errorBody() - ?.string() - _reportDetailUiState.value = errorMessage?.let { - ReportDetailUiState.ShowError( - it - ) - } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(response: FullParameterListResponse) { - _reportDetailUiState.value = - parameterName?.let { ReportDetailUiState.ShowProduct(response, it) } - } - }) - - } - - fun fetchRunReportWithQuery(reportName: String?, options: MutableMap) { - _reportDetailUiState.value = ReportDetailUiState.ShowProgressbar - repository.getRunReportWithQuery(reportName, options) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - try { - if (e is HttpException) { - val errorMessage = e.response()?.errorBody() - ?.string() - _reportDetailUiState.value = errorMessage?.let { - ReportDetailUiState.ShowError( - it - ) - } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(response: FullParameterListResponse) { - _reportDetailUiState.value = ReportDetailUiState.ShowRunReport(response) - } - }) - - } - - /** - * Method to filter Values of spinners with associated integer codes - * - * @param response List of DataRows - * @param values List of corresponding String values to be shown in Spinner - * @return HashMap of String values with the corresponding integer code - */ - fun filterIntHashMapForSpinner( - response: List?, - values: ArrayList - ): HashMap { - val map = HashMap() - values.clear() - Observable.from(response) - .subscribe { dataRow -> - val id = dataRow.row[0].toInt() - val value = dataRow.row[1] - values.add(value) - map[value] = id - } - return map - } - - /** - * Method to filter out values for the Spinners. - * - * @param response List of DataRows - * @param values List of the corresponding values - * @return HashMap of value and currency code pairs. - */ - fun filterStringHashMapForSpinner( - response: List?, - values: ArrayList - ): HashMap { - val map = HashMap() - values.clear() - Observable.from(response) - .subscribe { dataRow -> - val code = dataRow.row[0] - val value = dataRow.row[1] - values.add(value) - map[value] = code - } - return map - } -} \ No newline at end of file