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 f95efe5b2e5..f0a2dc283fc 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 @@ -5,11 +5,13 @@ import com.mifos.core.data.repository.CheckerInboxTasksRepository import com.mifos.core.data.repository.GroupDetailsRepository import com.mifos.core.data.repository.GroupsListRepository import com.mifos.core.data.repository.NewIndividualCollectionSheetRepository +import com.mifos.core.data.repository.ReportCategoryRepository import com.mifos.core.data.repository_imp.CenterListRepositoryImp import com.mifos.core.data.repository_imp.CheckerInboxTasksRepositoryImp import com.mifos.core.data.repository_imp.GroupDetailsRepositoryImp import com.mifos.core.data.repository_imp.GroupsListRepositoryImpl import com.mifos.core.data.repository_imp.NewIndividualCollectionSheetRepositoryImp +import com.mifos.core.data.repository_imp.ReportCategoryRepositoryImp import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -31,8 +33,11 @@ abstract class DataModule { ): GroupsListRepository @Binds - internal abstract fun provideGroupDetailsRepository(impl : GroupDetailsRepositoryImp) : GroupDetailsRepository - + internal abstract fun provideGroupDetailsRepository(impl: GroupDetailsRepositoryImp): GroupDetailsRepository + @Binds internal abstract fun bindCenterListRepository(impl: CenterListRepositoryImp): CenterListRepository + + @Binds + internal abstract fun bindReportCategoryRepository(impl: ReportCategoryRepositoryImp): ReportCategoryRepository } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryRepository.kt b/core/data/src/main/java/com/mifos/core/data/repository/ReportCategoryRepository.kt similarity index 53% rename from mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryRepository.kt rename to core/data/src/main/java/com/mifos/core/data/repository/ReportCategoryRepository.kt index 71e46dc6fcb..303d97a91cf 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryRepository.kt +++ b/core/data/src/main/java/com/mifos/core/data/repository/ReportCategoryRepository.kt @@ -1,17 +1,16 @@ -package com.mifos.mifosxdroid.online.runreports.reportcategory +package com.mifos.core.data.repository import com.mifos.core.objects.runreports.client.ClientReportTypeItem -import rx.Observable /** * Created by Aditya Gupta on 12/08/23. */ interface ReportCategoryRepository { - fun getReportCategories( - reportCategory: String?, + suspend fun getReportCategories( + reportCategory: String, genericResultSet: Boolean, parameterType: Boolean - ): Observable> + ): List } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryRepositoryImp.kt b/core/data/src/main/java/com/mifos/core/data/repository_imp/ReportCategoryRepositoryImp.kt similarity index 69% rename from mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryRepositoryImp.kt rename to core/data/src/main/java/com/mifos/core/data/repository_imp/ReportCategoryRepositoryImp.kt index 2babebde6c5..5e020b8050d 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryRepositoryImp.kt +++ b/core/data/src/main/java/com/mifos/core/data/repository_imp/ReportCategoryRepositoryImp.kt @@ -1,8 +1,8 @@ -package com.mifos.mifosxdroid.online.runreports.reportcategory +package com.mifos.core.data.repository_imp +import com.mifos.core.data.repository.ReportCategoryRepository import com.mifos.core.network.datamanager.DataManagerRunReport import com.mifos.core.objects.runreports.client.ClientReportTypeItem -import rx.Observable import javax.inject.Inject /** @@ -11,13 +11,11 @@ import javax.inject.Inject class ReportCategoryRepositoryImp @Inject constructor(private val dataManager: DataManagerRunReport) : ReportCategoryRepository { - override fun getReportCategories( - reportCategory: String?, + override suspend fun getReportCategories( + reportCategory: String, genericResultSet: Boolean, parameterType: Boolean - ): Observable> { + ): List { return dataManager.getReportCategories(reportCategory, genericResultSet, parameterType) } - - } \ No newline at end of file diff --git a/core/designsystem/src/main/java/com/mifos/core/designsystem/icon/MifosIcon.kt b/core/designsystem/src/main/java/com/mifos/core/designsystem/icon/MifosIcon.kt index ba52728c9e3..ced953edb5e 100644 --- a/core/designsystem/src/main/java/com/mifos/core/designsystem/icon/MifosIcon.kt +++ b/core/designsystem/src/main/java/com/mifos/core/designsystem/icon/MifosIcon.kt @@ -2,7 +2,13 @@ package com.mifos.core.designsystem.icon import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Add +import androidx.compose.material.icons.rounded.ArrowBackIosNew +import androidx.compose.material.icons.rounded.KeyboardArrowDown +import androidx.compose.material.icons.rounded.KeyboardArrowUp object MifosIcons { val Add = Icons.Rounded.Add + val arrowUp = Icons.Rounded.KeyboardArrowUp + val arrowDown = Icons.Rounded.KeyboardArrowDown + val arrowBack = Icons.Rounded.ArrowBackIosNew } \ No newline at end of file diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportCategoryUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportCategoryUseCase.kt new file mode 100644 index 00000000000..cac035557b5 --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetReportCategoryUseCase.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.ReportCategoryRepository +import com.mifos.core.objects.runreports.client.ClientReportTypeItem +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetReportCategoryUseCase @Inject constructor(private val repository: ReportCategoryRepository) { + + suspend operator fun invoke( + reportCategory: String, + genericResultSet: Boolean, + parameterType: Boolean + ): Flow>> = flow { + try { + emit(Resource.Loading()) + val response = + repository.getReportCategories(reportCategory, genericResultSet, parameterType) + 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 1d7ae194e89..6050eb4d7c5 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 @@ -13,11 +13,11 @@ import javax.inject.Singleton */ @Singleton class DataManagerRunReport @Inject constructor(val mBaseApiManager: BaseApiManager) { - fun getReportCategories( + suspend fun getReportCategories( reportCategory: String?, genericResultSet: Boolean, parameterType: Boolean - ): Observable> { + ): List { return mBaseApiManager.runReportsService.getReportCategories( reportCategory, genericResultSet, parameterType 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 149ec9dc111..5f960d08d0d 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 @@ -22,11 +22,11 @@ interface RunReportsService { * @return List of ClientReportTypeItem */ @GET(APIEndPoint.RUN_REPORTS + "/reportCategoryList") - fun getReportCategories( + suspend fun getReportCategories( @Query("R_reportCategory") category: String?, @Query("genericResultSet") genericResultSet: Boolean, @Query("parameterType") parameterType: Boolean - ): Observable> + ): List /** * Endpoint to fetch FullParameter list after fetching the categories. diff --git a/feature/report/.gitignore b/feature/report/.gitignore new file mode 100644 index 00000000000..42afabfd2ab --- /dev/null +++ b/feature/report/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/report/build.gradle.kts b/feature/report/build.gradle.kts new file mode 100644 index 00000000000..5860cc922cd --- /dev/null +++ b/feature/report/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + alias(libs.plugins.mifos.android.feature) + alias(libs.plugins.mifos.android.library.compose) + alias(libs.plugins.mifos.android.library.jacoco) +} + +android { + namespace = "com.mifos.feature.report" +} + +dependencies { + + implementation(projects.core.domain) + + //DBFlow dependencies + kapt(libs.dbflow.processor) + implementation(libs.dbflow) + kapt(libs.github.dbflow.processor) + testImplementation(libs.hilt.android.testing) + testImplementation(projects.core.testing) + + androidTestImplementation(projects.core.testing) +} \ No newline at end of file diff --git a/feature/report/consumer-rules.pro b/feature/report/consumer-rules.pro new file mode 100644 index 00000000000..e69de29bb2d diff --git a/feature/report/proguard-rules.pro b/feature/report/proguard-rules.pro new file mode 100644 index 00000000000..481bb434814 --- /dev/null +++ b/feature/report/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/feature/report/src/androidTest/java/com/mifos/feature/report/ExampleInstrumentedTest.kt b/feature/report/src/androidTest/java/com/mifos/feature/report/ExampleInstrumentedTest.kt new file mode 100644 index 00000000000..9e488c909c7 --- /dev/null +++ b/feature/report/src/androidTest/java/com/mifos/feature/report/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.mifos.feature.report + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.mifos.feature.report.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/feature/report/src/main/AndroidManifest.xml b/feature/report/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..a5918e68abc --- /dev/null +++ b/feature/report/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportScreen.kt b/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportScreen.kt new file mode 100644 index 00000000000..48ad2fc9789 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportScreen.kt @@ -0,0 +1,353 @@ +@file:OptIn(ExperimentalMaterial3Api::class) + +package com.mifos.feature.report.run_report + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +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.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +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.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.text.style.TextAlign +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.designsystem.component.MifosCircularProgress +import com.mifos.core.designsystem.component.MifosMenuDropDownItem +import com.mifos.core.designsystem.component.MifosScaffold +import com.mifos.core.designsystem.component.MifosSweetError +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.client.ClientReportTypeItem +import com.mifos.feature.report.R + +@Composable +fun RunReportScreen( + onBackPressed: () -> Unit, + onReportClick: (ClientReportTypeItem) -> Unit +) { + + val viewModel: RunReportViewModel = hiltViewModel() + val state by viewModel.runReportUiState.collectAsStateWithLifecycle() + var category by rememberSaveable { mutableStateOf(MenuItems.Client.name) } + + LaunchedEffect(Unit) { + viewModel.fetchCategories( + reportCategory = category, + genericResultSet = false, + parameterType = true + ) + } + + RunReportScreen( + state = state, + onBackPressed = onBackPressed, + onMenuClick = { + category = it.name + viewModel.fetchCategories( + reportCategory = category, + genericResultSet = false, + parameterType = true + ) + }, + onRetry = { + viewModel.fetchCategories( + reportCategory = category, + genericResultSet = false, + parameterType = true + ) + }, + onReportClick = onReportClick + ) +} + + +@Composable +private fun RunReportScreen( + state: RunReportUiState, + onBackPressed: () -> Unit, + onMenuClick: (MenuItems) -> Unit, + onRetry: () -> Unit, + onReportClick: (ClientReportTypeItem) -> Unit +) { + + val snackbarHostState = remember { SnackbarHostState() } + var showMenu by remember { mutableStateOf(false) } + var menuTitle by rememberSaveable { mutableStateOf(MenuItems.Client.name) } + + MifosScaffold( + topBar = { + TopAppBar( + colors = TopAppBarDefaults.mediumTopAppBarColors(containerColor = White), + navigationIcon = { + IconButton( + onClick = { onBackPressed() }, + ) { + Icon( + imageVector = MifosIcons.arrowBack, + contentDescription = null, + tint = Black, + ) + } + }, + title = { + Row( + modifier = Modifier.clickable { + showMenu = showMenu.not() + }, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = menuTitle, + style = TextStyle( + fontSize = 24.sp, + fontWeight = FontWeight.Medium, + fontStyle = FontStyle.Normal + ), + color = Black, + textAlign = TextAlign.Start + ) + Spacer(modifier = Modifier.width(8.dp)) + Icon( + imageVector = if (showMenu) MifosIcons.arrowUp else MifosIcons.arrowDown, + contentDescription = null + ) + } + DropdownMenu( + modifier = Modifier.background(White), + expanded = showMenu, + onDismissRequest = { showMenu = false } + ) { + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_client)) { + onMenuClick(MenuItems.Client) + menuTitle = MenuItems.Client.name + showMenu = false + } + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_loan)) { + onMenuClick(MenuItems.Loan) + menuTitle = MenuItems.Loan.name + showMenu = false + } + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_savings)) { + onMenuClick(MenuItems.Savings) + menuTitle = MenuItems.Savings.name + showMenu = false + } + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_fund)) { + onMenuClick(MenuItems.Fund) + menuTitle = MenuItems.Fund.name + showMenu = false + } + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_accounting)) { + onMenuClick(MenuItems.Accounting) + menuTitle = MenuItems.Accounting.name + showMenu = false + } + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_xbrl)) { + onMenuClick(MenuItems.XBRL) + menuTitle = MenuItems.XBRL.name + showMenu = false + } + MifosMenuDropDownItem(option = stringResource(id = R.string.feature_report_all)) { + onMenuClick(MenuItems.All) + menuTitle = MenuItems.All.name + showMenu = false + } + } + }, + actions = {} + ) + }, + snackbarHostState = snackbarHostState + ) { paddingValues -> + Column(modifier = Modifier.padding(paddingValues)) { + when (state) { + is RunReportUiState.Error -> MifosSweetError(message = stringResource(id = state.message)) { + onRetry() + } + + is RunReportUiState.Loading -> { + MifosCircularProgress() + } + + is RunReportUiState.RunReports -> { + RunReportContent(runReports = state.runReports, onReportClick = onReportClick) + } + } + } + } + +} + +@Composable +fun RunReportContent( + runReports: List, + onReportClick: (ClientReportTypeItem) -> Unit +) { + LazyColumn { + items(runReports.size) { index -> + RunReportCardItem(report = runReports[index], onReportClick = onReportClick) + } + } +} + + +@Composable +fun RunReportCardItem( + report: ClientReportTypeItem, + onReportClick: (ClientReportTypeItem) -> Unit +) { + OutlinedCard( + modifier = Modifier + .padding(8.dp) + .clickable { + onReportClick(report) + }, + 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) + ) { + report.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 = report.report_type.toString(), + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + color = DarkGray + ) + ) + Text( + text = report.report_category.toString(), + style = TextStyle( + fontSize = 14.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal, + color = DarkGray + ) + ) + } + } + } + } +} + + +enum class MenuItems { + Client, + Loan, + Savings, + Fund, + Accounting, + XBRL, + All +} + + +class RunReportUiStateProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + RunReportUiState.Loading, + RunReportUiState.Error(R.string.feature_report_failed_to_fetch_reports), + RunReportUiState.RunReports(sampleRunReports) + ) +} + +@Preview(showBackground = true) +@Composable +private fun RunReportPreview( + @PreviewParameter(RunReportUiStateProvider::class) state: RunReportUiState +) { + RunReportScreen( + state = state, + onBackPressed = {}, + onMenuClick = {}, + onRetry = {}, + onReportClick = {} + ) +} + +val sampleRunReports = List(10) { + ClientReportTypeItem( + report_name = "Report $it", + report_type = "Type $it", + report_category = "Category $it" + ) +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportUiState.kt b/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportUiState.kt new file mode 100644 index 00000000000..85b48ea0a96 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportUiState.kt @@ -0,0 +1,12 @@ +package com.mifos.feature.report.run_report + +import com.mifos.core.objects.runreports.client.ClientReportTypeItem + +sealed class RunReportUiState { + + data object Loading : RunReportUiState() + + data class Error(val message : Int) : RunReportUiState() + + data class RunReports(val runReports: List) : RunReportUiState() +} \ No newline at end of file diff --git a/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportViewModel.kt b/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportViewModel.kt new file mode 100644 index 00000000000..684ebf7de46 --- /dev/null +++ b/feature/report/src/main/java/com/mifos/feature/report/run_report/RunReportViewModel.kt @@ -0,0 +1,53 @@ +package com.mifos.feature.report.run_report + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mifos.core.common.utils.Resource +import com.mifos.core.domain.use_cases.GetReportCategoryUseCase +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 RunReportViewModel @Inject constructor( + private val getReportCategoryUseCase: GetReportCategoryUseCase +) : ViewModel() { + + private val _runReportUiState = MutableStateFlow(RunReportUiState.Loading) + val runReportUiState = _runReportUiState.asStateFlow() + + + fun fetchCategories( + reportCategory: String, + genericResultSet: Boolean, + parameterType: Boolean + ) = viewModelScope.launch(Dispatchers.IO) { + getReportCategoryUseCase( + reportCategory, + genericResultSet, + parameterType + ).collect { result -> + when (result) { + is Resource.Error -> _runReportUiState.value = + RunReportUiState.Error(R.string.feature_report_failed_to_fetch_reports) + + is Resource.Loading -> _runReportUiState.value = RunReportUiState.Loading + + is Resource.Success -> { + result.data?.let { reports -> + if (reports.isNotEmpty()) { + _runReportUiState.value = RunReportUiState.RunReports(reports) + } else { + _runReportUiState.value = + RunReportUiState.Error(R.string.feature_report_no_reports_found) + } + } + } + } + } + } +} \ No newline at end of file diff --git a/feature/report/src/main/res/drawable/feature_report_ic_report_item.xml b/feature/report/src/main/res/drawable/feature_report_ic_report_item.xml new file mode 100644 index 00000000000..e30587f4381 --- /dev/null +++ b/feature/report/src/main/res/drawable/feature_report_ic_report_item.xml @@ -0,0 +1,9 @@ + + + \ 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 new file mode 100644 index 00000000000..513ff719e0c --- /dev/null +++ b/feature/report/src/main/res/values/strings.xml @@ -0,0 +1,15 @@ + + + + Failed to Fetch Reports + Client + Loan + Savings + Fund + Accounting + XBRL + All + + No Reports Found + + \ No newline at end of file diff --git a/feature/report/src/test/java/com/mifos/feature/report/ExampleUnitTest.kt b/feature/report/src/test/java/com/mifos/feature/report/ExampleUnitTest.kt new file mode 100644 index 00000000000..90cc6cda4f3 --- /dev/null +++ b/feature/report/src/test/java/com/mifos/feature/report/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.mifos.feature.report + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/mifosng-android/build.gradle.kts b/mifosng-android/build.gradle.kts index 1a514e5017e..cb7ac273dc5 100644 --- a/mifosng-android/build.gradle.kts +++ b/mifosng-android/build.gradle.kts @@ -134,6 +134,7 @@ dependencies { implementation(projects.feature.groups) implementation(projects.feature.settings) implementation(projects.feature.center) + implementation(projects.feature.report) implementation(projects.core.common) implementation(projects.core.ui) 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 46639145ad1..a83becee7b9 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 @@ -95,8 +95,6 @@ import com.mifos.mifosxdroid.activity.pathtracking.PathTrackingRepository import com.mifos.mifosxdroid.activity.pathtracking.PathTrackingRepositoryImp import com.mifos.mifosxdroid.activity.pinpointclient.PinPointClientRepository import com.mifos.mifosxdroid.activity.pinpointclient.PinPointClientRepositoryImp -import com.mifos.mifosxdroid.online.runreports.reportcategory.ReportCategoryRepository -import com.mifos.mifosxdroid.online.runreports.reportcategory.ReportCategoryRepositoryImp import com.mifos.mifosxdroid.online.runreports.reportdetail.ReportDetailRepository import com.mifos.mifosxdroid.online.runreports.reportdetail.ReportDetailRepositoryImp import com.mifos.mifosxdroid.online.savingsaccountactivate.SavingsAccountActivateRepository @@ -352,11 +350,6 @@ class RepositoryModule { return ReportDetailRepositoryImp(dataManager) } - @Provides - fun providesReportCategoryRepository(dataManager: DataManagerRunReport): ReportCategoryRepository { - return ReportCategoryRepositoryImp(dataManager) - } - @Provides fun providesLoanRepaymentScheduleRepository(dataManager: DataManager): LoanRepaymentScheduleRepository { return LoanRepaymentScheduleRepositoryImp(dataManager) diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryFragment.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryFragment.kt index 43c45496518..2156b04178b 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryFragment.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryFragment.kt @@ -1,22 +1,16 @@ package com.mifos.mifosxdroid.online.runreports.reportcategory -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -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.recyclerview.widget.LinearLayoutManager -import com.mifos.core.common.utils.Constants import com.mifos.core.objects.runreports.client.ClientReportTypeItem -import com.mifos.mifosxdroid.adapters.ClientReportAdapter +import com.mifos.feature.report.run_report.RunReportScreen import com.mifos.mifosxdroid.core.MifosBaseFragment -import com.mifos.mifosxdroid.core.util.Toaster.show -import com.mifos.mifosxdroid.databinding.FragmentRunreportBinding import dagger.hilt.android.AndroidEntryPoint /** @@ -25,94 +19,42 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class ReportCategoryFragment : MifosBaseFragment() { - private lateinit var binding: FragmentRunreportBinding - - private lateinit var viewModel: ReportCategoryViewModel - - private var reportAdapter: ClientReportAdapter? = null - private var reportTypeItems: List? = null - private var reportCategory: String? = null - private var broadCastNewMessage: BroadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - reportCategory = intent.getStringExtra(Constants.REPORT_CATEGORY) - viewModel.fetchCategories( - reportCategory, - genericResultSet = false, - parameterType = true - ) - } - } - - override fun onResume() { - super.onResume() - requireActivity().registerReceiver( - broadCastNewMessage, - IntentFilter(Constants.ACTION_REPORT) - ) - } - - override fun onPause() { - super.onPause() - requireActivity().unregisterReceiver(broadCastNewMessage) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = FragmentRunreportBinding.inflate(inflater, container, false) - setHasOptionsMenu(true) - viewModel = ViewModelProvider(this)[ReportCategoryViewModel::class.java] - viewModel.fetchCategories(reportCategory, genericResultSet = false, parameterType = true) - - viewModel.reportCategoryUiState.observe(viewLifecycleOwner) { - when (it) { - is ReportCategoryUiState.ShowError -> { - showProgressbar(false) - showError(it.message) - } - - is ReportCategoryUiState.ShowProgressbar -> showProgressbar(true) - - is ReportCategoryUiState.ShowReportCategories -> { - showProgressbar(false) - showReportCategories(it.clientReportTypeItems) - } + return ComposeView(requireContext()).apply { + setViewCompositionStrategy( + ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed + ) + setContent { + RunReportScreen( + onBackPressed = { + requireActivity().onBackPressed() + }, + onReportClick = { + openDetailFragment(it) + } + ) } } - - return binding.root - } - - private fun showError(error: String) { - show(binding.root, error) } - private fun showReportCategories(reportTypes: List) { - reportTypeItems = reportTypes - val layoutManager = LinearLayoutManager(context) - binding.recyclerReport.layoutManager = layoutManager - reportAdapter = ClientReportAdapter { position: Int -> - openDetailFragment(position) - null - } - binding.recyclerReport.adapter = reportAdapter - reportAdapter?.setReportItems(reportTypes) - reportAdapter?.notifyDataSetChanged() + override fun onResume() { + super.onResume() + (requireActivity() as AppCompatActivity).supportActionBar?.hide() } - private fun openDetailFragment(pos: Int) { - val action = reportTypeItems?.getOrNull(pos)?.let { - ReportCategoryFragmentDirections.actionReportCategoryFragmentToReportDetailFragment(it) - } - action?.let { findNavController().navigate(it) } + override fun onStop() { + super.onStop() + (requireActivity() as AppCompatActivity).supportActionBar?.show() } - private fun showProgressbar(b: Boolean) { - if (b) { - showMifosProgressDialog() - } else { - hideMifosProgressDialog() - } + private fun openDetailFragment(runReport: ClientReportTypeItem) { + val action = + ReportCategoryFragmentDirections.actionReportCategoryFragmentToReportDetailFragment( + runReport + ) + findNavController().navigate(action) } } \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryUiState.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryUiState.kt deleted file mode 100644 index 5d426c668c7..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryUiState.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.mifos.mifosxdroid.online.runreports.reportcategory - -import com.mifos.core.objects.runreports.client.ClientReportTypeItem - -/** - * Created by Aditya Gupta on 12/08/23. - */ -sealed class ReportCategoryUiState { - - data object ShowProgressbar : ReportCategoryUiState() - - data class ShowError(val message: String) : ReportCategoryUiState() - - data class ShowReportCategories(val clientReportTypeItems: List) : - ReportCategoryUiState() - - -} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryViewModel.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryViewModel.kt deleted file mode 100644 index 82a7ffc0ea3..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/runreports/reportcategory/ReportCategoryViewModel.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.mifos.mifosxdroid.online.runreports.reportcategory - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.mifos.core.objects.runreports.client.ClientReportTypeItem -import dagger.hilt.android.lifecycle.HiltViewModel -import retrofit2.HttpException -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 ReportCategoryViewModel @Inject constructor(private val repository: ReportCategoryRepository) : - ViewModel() { - - private val _reportCategoryUiState = MutableLiveData() - - val reportCategoryUiState: LiveData - get() = _reportCategoryUiState - - fun fetchCategories( - reportCategory: String?, - genericResultSet: Boolean, - parameterType: Boolean - ) { - _reportCategoryUiState.value = ReportCategoryUiState.ShowProgressbar - repository.getReportCategories( - reportCategory, genericResultSet, - 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() - _reportCategoryUiState.value = errorMessage?.let { - ReportCategoryUiState.ShowError( - it - ) - } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(clientReportTypeItems: List) { - _reportCategoryUiState.value = - ReportCategoryUiState.ShowReportCategories(clientReportTypeItems) - } - }) - - } - - /** - * Method to filter unique ClientReportTypeItems from the given list - * - * @param list List of ClientReportTypeItems retrieved from server - * @return List of ClientReportTypeItems with unique items based on their Id. - */ - private fun filterUniques(list: List): ArrayList { - val map: MutableMap = LinkedHashMap() - for (item in list) { - map[item.report_id] = item - } - val uniques = ArrayList() - uniques.addAll(map.values) - return uniques - } -} \ No newline at end of file diff --git a/mifosng-android/src/main/res/layout/item_client_runreport.xml b/mifosng-android/src/main/res/layout/item_client_runreport.xml index 442ba6f18bd..3ae436dd968 100644 --- a/mifosng-android/src/main/res/layout/item_client_runreport.xml +++ b/mifosng-android/src/main/res/layout/item_client_runreport.xml @@ -29,7 +29,7 @@ android:id="@+id/iv_image" android:layout_width="wrap_content" android:layout_height="wrap_content" - app:srcCompat="@drawable/ic_report_item" /> + app:srcCompat="@drawable/feature_report_ic_report_item" /> diff --git a/mifosng-android/src/main/res/menu/menu_nav_drawer.xml b/mifosng-android/src/main/res/menu/menu_nav_drawer.xml index 8ac1f28c57d..4573c2f9c0e 100644 --- a/mifosng-android/src/main/res/menu/menu_nav_drawer.xml +++ b/mifosng-android/src/main/res/menu/menu_nav_drawer.xml @@ -27,7 +27,7 @@