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 44fd07a73ca..1835faa31c1 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 @@ -15,11 +15,12 @@ import com.mifos.core.data.repository.GroupListRepository import com.mifos.core.data.repository.GroupsListRepository import com.mifos.core.data.repository.IndividualCollectionSheetDetailsRepository import com.mifos.core.data.repository.LoanAccountRepository +import com.mifos.core.data.repository.LoanChargeRepository 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_imp.ActivateRepositoryImp import com.mifos.core.data.repository.ReportDetailRepository +import com.mifos.core.data.repository_imp.ActivateRepositoryImp import com.mifos.core.data.repository_imp.CenterDetailsRepositoryImp import com.mifos.core.data.repository_imp.CenterListRepositoryImp import com.mifos.core.data.repository_imp.CheckerInboxRepositoryImp @@ -33,6 +34,7 @@ import com.mifos.core.data.repository_imp.GroupListRepositoryImp import com.mifos.core.data.repository_imp.GroupsListRepositoryImpl import com.mifos.core.data.repository_imp.IndividualCollectionSheetDetailsRepositoryImp import com.mifos.core.data.repository_imp.LoanAccountRepositoryImp +import com.mifos.core.data.repository_imp.LoanChargeRepositoryImp import com.mifos.core.data.repository_imp.NewIndividualCollectionSheetRepositoryImp import com.mifos.core.data.repository_imp.PathTrackingRepositoryImp import com.mifos.core.data.repository_imp.ReportCategoryRepositoryImp @@ -98,7 +100,10 @@ abstract class DataModule { @Binds internal abstract fun bindIndividualCollectionSheetDetailsRepositoryImp(impl: IndividualCollectionSheetDetailsRepositoryImp): IndividualCollectionSheetDetailsRepository - + @Binds internal abstract fun bindGroupListRepository(impl: GroupListRepositoryImp): GroupListRepository + + @Binds + internal abstract fun bindLoanChargeRepository(impl: LoanChargeRepositoryImp): LoanChargeRepository } \ No newline at end of file diff --git a/core/data/src/main/java/com/mifos/core/data/repository/LoanChargeRepository.kt b/core/data/src/main/java/com/mifos/core/data/repository/LoanChargeRepository.kt new file mode 100644 index 00000000000..26196637909 --- /dev/null +++ b/core/data/src/main/java/com/mifos/core/data/repository/LoanChargeRepository.kt @@ -0,0 +1,12 @@ +package com.mifos.core.data.repository + +import com.mifos.core.objects.client.Charges + +/** + * Created by Aditya Gupta on 10/08/23. + */ +interface LoanChargeRepository { + + suspend fun getListOfLoanCharges(loanId: Int): List + +} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeRepositoryImp.kt b/core/data/src/main/java/com/mifos/core/data/repository_imp/LoanChargeRepositoryImp.kt similarity index 65% rename from mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeRepositoryImp.kt rename to core/data/src/main/java/com/mifos/core/data/repository_imp/LoanChargeRepositoryImp.kt index 6ac4ebd471c..4cfbaf2cdb3 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeRepositoryImp.kt +++ b/core/data/src/main/java/com/mifos/core/data/repository_imp/LoanChargeRepositoryImp.kt @@ -1,8 +1,8 @@ -package com.mifos.mifosxdroid.online.loancharge +package com.mifos.core.data.repository_imp +import com.mifos.core.data.repository.LoanChargeRepository import com.mifos.core.network.DataManager import com.mifos.core.objects.client.Charges -import rx.Observable import javax.inject.Inject /** @@ -11,7 +11,7 @@ import javax.inject.Inject class LoanChargeRepositoryImp @Inject constructor(private val dataManager: DataManager) : LoanChargeRepository { - override fun getListOfLoanCharges(loanId: Int): Observable> { + override suspend fun getListOfLoanCharges(loanId: Int): List { return dataManager.getListOfLoanCharges(loanId) } } \ No newline at end of file diff --git a/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetListOfLoanChargesUseCase.kt b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetListOfLoanChargesUseCase.kt new file mode 100644 index 00000000000..a9b9b88f901 --- /dev/null +++ b/core/domain/src/main/java/com/mifos/core/domain/use_cases/GetListOfLoanChargesUseCase.kt @@ -0,0 +1,21 @@ +package com.mifos.core.domain.use_cases + +import com.mifos.core.common.utils.Resource +import com.mifos.core.data.repository.LoanChargeRepository +import com.mifos.core.objects.client.Charges +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetListOfLoanChargesUseCase @Inject constructor(private val repository: LoanChargeRepository) { + + suspend operator fun invoke(loanId: Int): Flow>> = flow { + try { + emit(Resource.Loading()) + val response = repository.getListOfLoanCharges(loanId) + 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.kt b/core/network/src/main/java/com/mifos/core/network/DataManager.kt index 1e275a1d7e4..6a08f117bfa 100644 --- a/core/network/src/main/java/com/mifos/core/network/DataManager.kt +++ b/core/network/src/main/java/com/mifos/core/network/DataManager.kt @@ -175,7 +175,7 @@ class DataManager { return mBaseApiManager.loanApi.approveLoanApplication(loanId, loanApproval) } - fun getListOfLoanCharges(loanId: Int): Observable> { + suspend fun getListOfLoanCharges(loanId: Int): List { return mBaseApiManager.loanApi.getListOfLoanCharges(loanId) } diff --git a/core/network/src/main/java/com/mifos/core/network/services/LoanService.kt b/core/network/src/main/java/com/mifos/core/network/services/LoanService.kt index 4fa91cdcc0d..29061a8fef8 100644 --- a/core/network/src/main/java/com/mifos/core/network/services/LoanService.kt +++ b/core/network/src/main/java/com/mifos/core/network/services/LoanService.kt @@ -107,7 +107,7 @@ interface LoanService { ): Observable @GET(APIEndPoint.LOANS + "/{loanId}/" + APIEndPoint.CHARGES) - fun getListOfLoanCharges(@Path("loanId") loanId: Int): Observable> + suspend fun getListOfLoanCharges(@Path("loanId") loanId: Int): List @GET(APIEndPoint.CLIENTS + "/{clientId}/" + APIEndPoint.CHARGES) fun getListOfCharges(@Path("clientId") clientId: Int): Observable> diff --git a/feature/loan/build.gradle.kts b/feature/loan/build.gradle.kts index d4ce95f19f3..c7dbac3bc99 100644 --- a/feature/loan/build.gradle.kts +++ b/feature/loan/build.gradle.kts @@ -20,4 +20,6 @@ dependencies { testImplementation(projects.core.testing) androidTestImplementation(projects.core.testing) + + implementation(libs.androidx.material) } \ No newline at end of file diff --git a/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeScreen.kt b/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeScreen.kt new file mode 100644 index 00000000000..17059d68bd4 --- /dev/null +++ b/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeScreen.kt @@ -0,0 +1,247 @@ +@file:OptIn(ExperimentalMaterialApi::class) + +package com.mifos.feature.loan.loan_charge + +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.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +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.ui.Alignment +import androidx.compose.ui.Modifier +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.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.objects.client.Charges +import com.mifos.core.ui.components.MifosEmptyUi +import com.mifos.feature.loan.R + +@Composable +fun LoanChargeScreen(loanAccountNumber: Int, onBackPressed: () -> Unit) { + + val viewModel: LoanChargeViewModel = hiltViewModel() + val state by viewModel.loanChargeUiState.collectAsStateWithLifecycle() + val refreshState by viewModel.isRefreshing.collectAsStateWithLifecycle() + + LaunchedEffect(Unit) { + viewModel.loadLoanChargesList(loanAccountNumber) + } + + LoanChargeScreen( + state = state, + onBackPressed = onBackPressed, + onRetry = { + viewModel.loadLoanChargesList(loanAccountNumber) + }, + refreshState = refreshState, + onRefresh = { + viewModel.refreshLoanChargeList(loanAccountNumber) + } + ) + +} + +@Composable +fun LoanChargeScreen( + state: LoanChargeUiState, + onBackPressed: () -> Unit, + onRetry: () -> Unit, + refreshState: Boolean, + onRefresh: () -> Unit, +) { + val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) } + val pullRefreshState = rememberPullRefreshState( + refreshing = refreshState, + onRefresh = onRefresh + ) + + MifosScaffold( + icon = MifosIcons.arrowBack, + title = stringResource(id = R.string.feature_loan_loan_charges), + onBackPressed = onBackPressed, + actions = { + IconButton(onClick = { + // TODO Implement Loan Charges Add Dialog + }) { + Icon(imageVector = MifosIcons.Add, contentDescription = null) + } + }, + snackbarHostState = snackbarHostState + ) { paddingValues -> + Column(modifier = Modifier.padding(paddingValues)) { + Box(modifier = Modifier.pullRefresh(pullRefreshState)) { + when (state) { + is LoanChargeUiState.Error -> MifosSweetError(message = stringResource(id = state.message)) { + onRetry() + } + + is LoanChargeUiState.Loading -> MifosCircularProgress() + + is LoanChargeUiState.LoanChargesList -> { + if (state.loanCharges.isEmpty()) { + MifosEmptyUi( + text = stringResource(id = R.string.feature_loan_no_loan_charges), + icon = MifosIcons.fileTask + ) + } else { + LoanChargesContent(loanCharges = state.loanCharges) + } + } + } + + PullRefreshIndicator( + refreshing = refreshState, + state = pullRefreshState, + modifier = Modifier.align(Alignment.TopCenter) + ) + } + } + } +} + +@Composable +fun LoanChargesContent( + loanCharges: List +) { + LazyColumn { + items(loanCharges) { charges -> + LoanChargeItem( + charges = charges + ) + } + } +} + +@Composable +fun LoanChargeItem( + charges: Charges +) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + shape = RoundedCornerShape(0.dp), + elevation = CardDefaults.cardElevation(defaultElevation = 2.dp), + colors = CardDefaults.cardColors( + containerColor = BlueSecondary + ) + ) { + Spacer(modifier = Modifier.height(8.dp)) + MifosLoanChargeDetailsText( + stringResource(id = R.string.feature_loan_client_id), + charges.chargeId.toString() + ) + MifosLoanChargeDetailsText( + stringResource(id = R.string.feature_loan_charge_name), + charges.name ?: "" + ) + MifosLoanChargeDetailsText( + stringResource(id = R.string.feature_loan_charge_amount), + charges.amount.toString() + ) + MifosLoanChargeDetailsText( + stringResource(id = R.string.feature_loan_charge_due_date), + charges.formattedDueDate + ) + Spacer(modifier = Modifier.height(8.dp)) + } +} + +@Composable +fun MifosLoanChargeDetailsText(field: String, value: String) { + Row( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier + .weight(1f) + .padding(start = 16.dp), + text = field, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal + ), + color = Black, + textAlign = TextAlign.Start + ) + Text( + modifier = Modifier.weight(1f), + text = value, + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal + ), + color = DarkGray, + textAlign = TextAlign.Start + ) + } +} + +class LoanChargeUiStateProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + LoanChargeUiState.Loading, + LoanChargeUiState.Error(R.string.feature_loan_failed_to_load_loan_charges), + LoanChargeUiState.LoanChargesList(sampleLoanChargeList) + ) +} + + +@Preview(showBackground = true) +@Composable +private fun LoanChargeScreenPreview( + @PreviewParameter(LoanChargeUiStateProvider::class) state: LoanChargeUiState +) { + LoanChargeScreen( + state = state, + onBackPressed = {}, + onRetry = {}, + refreshState = false, + onRefresh = {} + ) +} + +val sampleLoanChargeList = List(10) { + Charges(name = "name $it", chargeId = it, amount = it.toDouble()) +} \ No newline at end of file diff --git a/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeUiState.kt b/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeUiState.kt new file mode 100644 index 00000000000..139166ad67d --- /dev/null +++ b/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeUiState.kt @@ -0,0 +1,15 @@ +package com.mifos.feature.loan.loan_charge + +import com.mifos.core.objects.client.Charges + +/** + * Created by Aditya Gupta on 10/08/23. + */ +sealed class LoanChargeUiState { + + data object Loading : LoanChargeUiState() + + data class Error(val message: Int) : LoanChargeUiState() + + data class LoanChargesList(val loanCharges: List) : LoanChargeUiState() +} \ No newline at end of file diff --git a/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeViewModel.kt b/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeViewModel.kt new file mode 100644 index 00000000000..43341dbf581 --- /dev/null +++ b/feature/loan/src/main/java/com/mifos/feature/loan/loan_charge/LoanChargeViewModel.kt @@ -0,0 +1,46 @@ +package com.mifos.feature.loan.loan_charge + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.mifos.core.common.utils.Resource +import com.mifos.core.domain.use_cases.GetListOfLoanChargesUseCase +import com.mifos.feature.loan.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 LoanChargeViewModel @Inject constructor( + private val getListOfLoanChargesUseCase: GetListOfLoanChargesUseCase +) : ViewModel() { + + private val _loanChargeUiState = MutableStateFlow(LoanChargeUiState.Loading) + val loanChargeUiState = _loanChargeUiState.asStateFlow() + + private val _isRefreshing = MutableStateFlow(false) + val isRefreshing = _isRefreshing.asStateFlow() + + fun refreshLoanChargeList(loanAccountNumber: Int) { + _isRefreshing.value = true + loadLoanChargesList(loanAccountNumber = loanAccountNumber) + _isRefreshing.value = false + } + + + fun loadLoanChargesList(loanAccountNumber: Int) = viewModelScope.launch(Dispatchers.IO) { + getListOfLoanChargesUseCase(loanAccountNumber).collect { result -> + when (result) { + is Resource.Error -> _loanChargeUiState.value = + LoanChargeUiState.Error(R.string.feature_loan_failed_to_load_loan_charges) + + is Resource.Loading -> _loanChargeUiState.value = LoanChargeUiState.Loading + + is Resource.Success -> _loanChargeUiState.value = + LoanChargeUiState.LoanChargesList(result.data ?: emptyList()) + } + } + } +} \ No newline at end of file diff --git a/feature/loan/src/main/res/values/strings.xml b/feature/loan/src/main/res/values/strings.xml index 1203121d9ea..a1d5b85e310 100644 --- a/feature/loan/src/main/res/values/strings.xml +++ b/feature/loan/src/main/res/values/strings.xml @@ -34,4 +34,13 @@ Failed to load loan Failed to load loan template Failed to create loan account + + Loan Charges + Failed to load loan charges + No Loan Charges Available for this client + + Client ID + Charge Name + Charge Amount + Charge Due Date \ 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 6572ce7dec6..caadce4a500 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 @@ -88,8 +88,6 @@ import com.mifos.mifosxdroid.online.loanaccountdisbursement.LoanAccountDisbursem import com.mifos.mifosxdroid.online.loanaccountdisbursement.LoanAccountDisbursementRepositoryImp import com.mifos.mifosxdroid.online.loanaccountsummary.LoanAccountSummaryRepository import com.mifos.mifosxdroid.online.loanaccountsummary.LoanAccountSummaryRepositoryImp -import com.mifos.mifosxdroid.online.loancharge.LoanChargeRepository -import com.mifos.mifosxdroid.online.loancharge.LoanChargeRepositoryImp import com.mifos.mifosxdroid.online.loanrepayment.LoanRepaymentRepository import com.mifos.mifosxdroid.online.loanrepayment.LoanRepaymentRepositoryImp import com.mifos.mifosxdroid.online.loanrepaymentschedule.LoanRepaymentScheduleRepository @@ -216,11 +214,6 @@ class RepositoryModule { return SurveyListRepositoryImp(dataManagerSurveys) } - @Provides - fun providesLoanChargeRepository(dataManager: DataManager): LoanChargeRepository { - return LoanChargeRepositoryImp(dataManager) - } - @Provides fun providesLoanAccountApprovalRepository(dataManager: DataManager): LoanAccountApprovalRepository { return LoanAccountApprovalRepositoryImp(dataManager) diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeFragment.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeFragment.kt index 61162aa1c83..92f84e71c24 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeFragment.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeFragment.kt @@ -6,43 +6,29 @@ package com.mifos.mifosxdroid.online.loancharge import android.os.Bundle import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuItem 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.navigation.fragment.navArgs -import androidx.recyclerview.widget.LinearLayoutManager -import com.mifos.core.objects.client.Charges -import com.mifos.mifosxdroid.R -import com.mifos.mifosxdroid.adapters.ChargeNameListAdapter -import com.mifos.mifosxdroid.core.EndlessRecyclerOnScrollListener +import com.mifos.feature.loan.loan_charge.LoanChargeScreen import com.mifos.mifosxdroid.core.MifosBaseFragment -import com.mifos.mifosxdroid.core.util.Toaster -import com.mifos.mifosxdroid.databinding.FragmentChargeListBinding -import com.mifos.mifosxdroid.dialogfragments.chargedialog.OnChargeCreateListener -import com.mifos.mifosxdroid.dialogfragments.loanchargedialog.LoanChargeDialogFragment -import com.mifos.utils.FragmentConstants import dagger.hilt.android.AndroidEntryPoint /** * Created by nellyk on 1/22/2016. */ @AndroidEntryPoint -class LoanChargeFragment : MifosBaseFragment(), OnChargeCreateListener { +class LoanChargeFragment : MifosBaseFragment() { - private lateinit var binding: FragmentChargeListBinding private val arg: LoanChargeFragmentArgs by navArgs() + private var loanAccountNumber: Int = 0 - private lateinit var viewModel: LoanChargeViewModel - - private var chargesList: MutableList = ArrayList() - private var mChargesNameListAdapter: ChargeNameListAdapter? = null - private var loanAccountNumber = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) loanAccountNumber = arg.loanAccountNumber - setChargesList(arg.chargesList.toMutableList()) } override fun onCreateView( @@ -50,147 +36,23 @@ class LoanChargeFragment : MifosBaseFragment(), OnChargeCreateListener { container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = FragmentChargeListBinding.inflate(inflater, container, false) - setHasOptionsMenu(true) - viewModel = ViewModelProvider(this)[LoanChargeViewModel::class.java] - val layoutManager = LinearLayoutManager(activity) - layoutManager.orientation = LinearLayoutManager.VERTICAL - binding.rvCharge.layoutManager = layoutManager - binding.rvCharge.setHasFixedSize(true) - - - //Loading LoanChargesList - viewModel.loadLoanChargesList(loanAccountNumber) - setToolbarTitle(getString(R.string.charges)) - /** - * Setting mApiRestCounter to 1 and send Refresh Request to Server - */ - binding.swipeContainer.setColorSchemeResources( - R.color.blue_light, - R.color.green_light, - R.color.orange_light, - R.color.red_light - ) - binding.swipeContainer.setOnRefreshListener { - viewModel.loadLoanChargesList(loanAccountNumber) - if (binding.swipeContainer.isRefreshing) binding.swipeContainer.isRefreshing = false - } - /** - * This is the LoadMore of the RecyclerView. It called When Last Element of RecyclerView - * is shown on the Screen. - * Increase the mApiRestCounter by 1 and Send Api Request to Server with Paged(True) - * and offset(mCenterList.size()) and limit(100). - */ - binding.rvCharge.addOnScrollListener(object : - EndlessRecyclerOnScrollListener(layoutManager) { - override fun onLoadMore(current_page: Int) { - - //Future Implementation - } - }) - - viewModel.loanChargeUiState.observe(viewLifecycleOwner) { - when (it) { - is LoanChargeUiState.ShowFetchingError -> { - showProgressbar(false) - showFetchingError(it.message) - } - - is LoanChargeUiState.ShowLoanChargesList -> { - showProgressbar(false) - showLoanChargesList(it.chargesPage) - } - - is LoanChargeUiState.ShowProgressbar -> showProgressbar(true) + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + LoanChargeScreen(loanAccountNumber = loanAccountNumber, onBackPressed = { + findNavController().popBackStack() + }) } } - - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - binding.noChargesIcon.setOnClickListener { - reloadOnError() - } - } - - /** - * Shows When mApiRestValue is 1 and Server Response is Null. - * Onclick Send Fresh Request for Center list. - */ - private fun reloadOnError() { - binding.llError.visibility = View.GONE - viewModel.loadLoanChargesList(loanAccountNumber) - } - - private fun setChargesList(chargesList: MutableList) { - this.chargesList = chargesList - } - - private fun showLoanChargesList(charges: MutableList) { - chargesList = charges - mChargesNameListAdapter = ChargeNameListAdapter(chargesList, loanAccountNumber) - binding.rvCharge.adapter = mChargesNameListAdapter - if (charges.size == 0) { - binding.llError.visibility = View.VISIBLE - binding.noChargesText.text = getString(R.string.message_no_charges_available) - binding.noChargesIcon.setImageResource(R.drawable.ic_assignment_turned_in_black_24dp) - } - } - - private fun showFetchingError(s: String) { - binding.llError.visibility = View.VISIBLE - binding.noChargesText.text = "$s\n Click to Refresh " - viewModel.loadLoanChargesList(loanAccountNumber) - Toaster.show(binding.root, s) - } - - private fun showProgressbar(b: Boolean) { - if (b) { - showMifosProgressBar() - } else { - hideMifosProgressBar() - } - } - - override fun onPrepareOptionsMenu(menu: Menu) { - menu.clear() - val menuItemAddNewLoanCharge = menu.add( - Menu.NONE, MENU_ITEM_ADD_NEW_LOAN_CHARGES, - Menu.NONE, getString(R.string.add_new) - ) - menuItemAddNewLoanCharge.icon = resources.getDrawable(R.drawable.ic_add_white_24dp) - menuItemAddNewLoanCharge.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) - super.onPrepareOptionsMenu(menu) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - val id = item.itemId - if (id == MENU_ITEM_ADD_NEW_LOAN_CHARGES) { - val loanChargeDialogFragment = LoanChargeDialogFragment - .newInstance(loanAccountNumber) - loanChargeDialogFragment.setOnChargeCreateListener(this) - val fragmentTransaction = requireActivity().supportFragmentManager - .beginTransaction() - fragmentTransaction.addToBackStack(FragmentConstants.FRAG_CHARGE_LIST) - loanChargeDialogFragment.show(fragmentTransaction, "Loan Charge Dialog Fragment") - } - return super.onOptionsItemSelected(item) - } - - override fun onChargeCreatedSuccess(charge: Charges) { - chargesList.add(charge) - Toaster.show(binding.root, getString(R.string.message_charge_created_success)) - mChargesNameListAdapter!!.notifyItemInserted(chargesList.size - 1) } - override fun onChargeCreatedFailure(errorMessage: String) { - Toaster.show(binding.root, errorMessage) + override fun onResume() { + super.onResume() + (requireActivity() as AppCompatActivity).supportActionBar?.hide() } - companion object { - const val MENU_ITEM_ADD_NEW_LOAN_CHARGES = 3000 + 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/loancharge/LoanChargeRepository.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeRepository.kt deleted file mode 100644 index 22bf7b85822..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeRepository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.mifos.mifosxdroid.online.loancharge - -import com.mifos.core.objects.client.Charges -import rx.Observable - -/** - * Created by Aditya Gupta on 10/08/23. - */ -interface LoanChargeRepository { - - fun getListOfLoanCharges(loanId: Int): Observable> - -} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeUiState.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeUiState.kt deleted file mode 100644 index 39ee5d3cfcb..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeUiState.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.mifos.mifosxdroid.online.loancharge - -import com.mifos.core.objects.client.Charges - -/** - * Created by Aditya Gupta on 10/08/23. - */ -sealed class LoanChargeUiState { - - data object ShowProgressbar : LoanChargeUiState() - - data class ShowFetchingError(val message: String) : LoanChargeUiState() - - data class ShowLoanChargesList(val chargesPage: MutableList) : LoanChargeUiState() - - -} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeViewModel.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeViewModel.kt deleted file mode 100644 index 0fff18e4b89..00000000000 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/loancharge/LoanChargeViewModel.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.mifos.mifosxdroid.online.loancharge - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.mifos.core.objects.client.Charges -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 10/08/23. - */ -@HiltViewModel -class LoanChargeViewModel @Inject constructor(private val repository: LoanChargeRepository) : - ViewModel() { - - private val _loanChargeUiState = MutableLiveData() - - val loanChargeUiState: LiveData - get() = _loanChargeUiState - - fun loadLoanChargesList(loanId: Int) { - _loanChargeUiState.value = LoanChargeUiState.ShowProgressbar - repository.getListOfLoanCharges(loanId) - .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() - _loanChargeUiState.value = - errorMessage?.let { LoanChargeUiState.ShowFetchingError(it) } - } - } catch (throwable: Throwable) { - RxJavaPlugins.getInstance().errorHandler.handleError(e) - } - } - - override fun onNext(chargesPage: List) { - _loanChargeUiState.value = - LoanChargeUiState.ShowLoanChargesList(chargesPage as MutableList) - } - }) - } - -} \ No newline at end of file diff --git a/mifosng-android/src/test/java/com/mifos/viewmodels/LoanChargeViewModelTest.kt b/mifosng-android/src/test/java/com/mifos/viewmodels/LoanChargeViewModelTest.kt deleted file mode 100644 index 745f07ca719..00000000000 --- a/mifosng-android/src/test/java/com/mifos/viewmodels/LoanChargeViewModelTest.kt +++ /dev/null @@ -1,85 +0,0 @@ -package com.mifos.viewmodels - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import androidx.lifecycle.Observer -import com.mifos.core.objects.client.Charges -import com.mifos.mifosxdroid.online.loancharge.LoanChargeRepository -import com.mifos.mifosxdroid.online.loancharge.LoanChargeUiState -import com.mifos.mifosxdroid.online.loancharge.LoanChargeViewModel -import com.mifos.mifosxdroid.util.RxSchedulersOverrideRule -import org.junit.After -import org.junit.Assert.* -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.MockitoAnnotations -import org.mockito.junit.MockitoJUnitRunner -import rx.Observable - -/** - * Created by Aditya Gupta on 02/09/23. - */ -@RunWith(MockitoJUnitRunner::class) -class LoanChargeViewModelTest { - - - @get:Rule - val overrideSchedulersRule = RxSchedulersOverrideRule() - - @get:Rule - val instantTaskExecutorRule = InstantTaskExecutorRule() - - @Mock - private lateinit var loanChargeRepository: LoanChargeRepository - - @Mock - private lateinit var loanChargeViewModel: LoanChargeViewModel - - @Mock - private lateinit var loanChargeUiStateObserver: Observer - - @Mock - private lateinit var mockChargesPage: List - - @Before - fun setUp() { - MockitoAnnotations.openMocks(this) - loanChargeViewModel = LoanChargeViewModel(loanChargeRepository) - loanChargeViewModel.loanChargeUiState.observeForever(loanChargeUiStateObserver) - } - - @Test - fun testLoadLoanChargesList_SuccessfulLoanChargesReceivedFromRepository_ReturnsSuccess() { - - Mockito.`when`(loanChargeRepository.getListOfLoanCharges(Mockito.anyInt())).thenReturn( - Observable.just(mockChargesPage) - ) - loanChargeViewModel.loadLoanChargesList(441) - Mockito.verify(loanChargeUiStateObserver).onChanged(LoanChargeUiState.ShowProgressbar) - Mockito.verify(loanChargeUiStateObserver, Mockito.never()) - .onChanged(LoanChargeUiState.ShowFetchingError("some error message")) - Mockito.verify(loanChargeUiStateObserver) - .onChanged(LoanChargeUiState.ShowLoanChargesList(mockChargesPage as MutableList)) - Mockito.verifyNoMoreInteractions(loanChargeUiStateObserver) - } - - @Test - fun testLoadLoanChargesList_UnSuccessfulLoanChargesReceivedFromRepository_ReturnsError() { - - Mockito.`when`(loanChargeRepository.getListOfLoanCharges(Mockito.anyInt())) - .thenReturn(Observable.error(RuntimeException("some error message"))) - loanChargeViewModel.loadLoanChargesList(441) - Mockito.verify(loanChargeUiStateObserver).onChanged(LoanChargeUiState.ShowProgressbar) - Mockito.verify(loanChargeUiStateObserver, Mockito.never()) - .onChanged(LoanChargeUiState.ShowLoanChargesList(mockChargesPage as MutableList)) - Mockito.verifyNoMoreInteractions(loanChargeUiStateObserver) - } - - @After - fun tearDown() { - loanChargeViewModel.loanChargeUiState.removeObserver(loanChargeUiStateObserver) - } -} \ No newline at end of file