diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationContent.kt b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationContent.kt index 028bca6446..1ce8de042f 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationContent.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationContent.kt @@ -60,7 +60,7 @@ fun ReviewLoanApplicationContent( title = stringResource(id = R.string.principal), description = String.format( Locale.getDefault(), - "%.2f", data.principal ?: 0, + "%.2f", data.principal ?: 0.0, ), descriptionStyle = MaterialTheme.typography.bodyMedium ) diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt index 3d890ac7fc..b79a2a0542 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt @@ -88,10 +88,11 @@ class ReviewLoanApplicationFragment : BaseFragment() { setContent { MifosMobileTheme { ReviewLoanApplicationScreen( - uiState = viewModel.reviewLoanApplicationUiState.value, - navigateBack = { activity?.supportFragmentManager?.popBackStack() }, - navigateBackWithSuccess = { activity?.finish() }, - submit = { viewModel.submitLoan() } + submit = { viewModel.submitLoan() }, + navigateBack = { reviewSuccess -> + if(reviewSuccess)activity?.finish() + else activity?.supportFragmentManager?.popBackStack() + } ) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationScreen.kt b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationScreen.kt index c77b87ba22..8a1d47b088 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationScreen.kt @@ -1,23 +1,28 @@ package org.mifos.mobile.ui.loan_review -import android.graphics.Color +import android.content.res.Configuration import android.widget.Toast import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource 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.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.mifos.mobile.R -import org.mifos.mobile.core.ui.component.EmptyDataView import org.mifos.mobile.core.ui.component.MifosProgressIndicator import org.mifos.mobile.core.ui.component.MifosTopBar import org.mifos.mobile.core.ui.component.NoInternet @@ -27,52 +32,70 @@ import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network +@Composable +fun ReviewLoanApplicationScreen( + viewModel: ReviewLoanApplicationViewModel = hiltViewModel(), + navigateBack: (isSuccess: Boolean) -> Unit, + submit: () -> Unit, +) { + val uiState by viewModel.reviewLoanApplicationUiState.collectAsStateWithLifecycle() + val data by viewModel.reviewLoanApplicationUiData.collectAsStateWithLifecycle() + + ReviewLoanApplicationScreen( + uiState = uiState, + data = data, + navigateBack = navigateBack, + submit = submit + ) +} + @Composable fun ReviewLoanApplicationScreen( uiState: ReviewLoanApplicationUiState, - navigateBack: () -> Unit, - navigateBackWithSuccess: () -> Unit, + data: ReviewLoanApplicationUiData, + navigateBack: (isSuccess: Boolean) -> Unit, submit: () -> Unit, ) { val context = LocalContext.current Column(modifier= Modifier.fillMaxSize()) { MifosTopBar( modifier= Modifier.fillMaxWidth(), - navigateBack = { navigateBack() }, + navigateBack = { navigateBack(false) }, title = { Text(text = stringResource(id = R.string.update_loan)) } ) - when (uiState) { - is ReviewLoanApplicationUiState.ShowContent -> { - ReviewLoanApplicationContent( - modifier = Modifier.padding(16.dp), - data = uiState.reviewLoanApplicationUiData, - submit = submit - ) - } - is ReviewLoanApplicationUiState.Loading -> { - MifosProgressIndicator(modifier = Modifier.fillMaxSize()) - } + Box(modifier = Modifier.weight(1f)) { + ReviewLoanApplicationContent(modifier = Modifier.padding(16.dp), data = data, submit = submit) - is ReviewLoanApplicationUiState.Error -> { - ErrorComponent(errorThrowable = uiState.throwable) - } + when (uiState) { + is ReviewLoanApplicationUiState.Initial -> { + // Data shown in UI + } - is ReviewLoanApplicationUiState.Success -> { - when (uiState.loanState) { - LoanState.CREATE -> - Toast.makeText(context, stringResource(id = R.string.loan_application_submitted_successfully), Toast.LENGTH_SHORT).show() + is ReviewLoanApplicationUiState.Loading -> { + MifosProgressIndicator(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background.copy(0.8f))) + } - LoanState.UPDATE -> - Toast.makeText(context, stringResource(id = R.string.loan_application_updated_successfully), Toast.LENGTH_SHORT).show() + is ReviewLoanApplicationUiState.Error -> { + ErrorComponent(errorThrowable = uiState.throwable) + } + + is ReviewLoanApplicationUiState.Success -> { + when (uiState.loanState) { + LoanState.CREATE -> + Toast.makeText(context, stringResource(id = R.string.loan_application_submitted_successfully), Toast.LENGTH_SHORT).show() + + LoanState.UPDATE -> + Toast.makeText(context, stringResource(id = R.string.loan_application_updated_successfully), Toast.LENGTH_SHORT).show() + } + navigateBack(true) } - navigateBackWithSuccess() } } } - } + @Composable fun ErrorComponent( errorThrowable: Throwable, @@ -85,21 +108,35 @@ fun ErrorComponent( isRetryEnabled = false, ) } else { - EmptyDataView( - modifier = Modifier.fillMaxSize(), - icon = R.drawable.ic_error_black_24dp, - error = R.string.something_went_wrong, - errorString = MFErrorParser.errorMessage(errorThrowable) - ) + LaunchedEffect(errorThrowable) { + val errorToast = MFErrorParser.errorMessage(errorThrowable) + Toast.makeText(context, errorToast, Toast.LENGTH_SHORT).show() + } } } -@Preview(showSystemUi = true) + +class UiStatesParameterProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + ReviewLoanApplicationUiState.Initial, + ReviewLoanApplicationUiState.Error(throwable = Throwable()), + ReviewLoanApplicationUiState.Loading, + ReviewLoanApplicationUiState.Success(loanState = LoanState.CREATE) + ) +} + + +@Preview(showSystemUi = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable -fun ReviewLoanApplicationScreenPreview() { +fun ReviewLoanApplicationScreenPreview( + @PreviewParameter(UiStatesParameterProvider::class) reviewLoanApplicationUiState: ReviewLoanApplicationUiState +) { MifosMobileTheme { - ReviewLoanApplicationScreen(uiState = ReviewLoanApplicationUiState - .ShowContent(ReviewLoanApplicationUiData()), {}, {}, {} + ReviewLoanApplicationScreen( + uiState = reviewLoanApplicationUiState, + data = ReviewLoanApplicationUiData(), + {}, {} ) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationViewModel.kt index 34a98b2635..c8c7f377ac 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationViewModel.kt @@ -6,6 +6,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch import org.mifos.mobile.models.payload.LoansPayload @@ -16,16 +18,16 @@ import javax.inject.Inject @HiltViewModel class ReviewLoanApplicationViewModel @Inject constructor( private val reviewLoanApplicationRepositoryImpl: ReviewLoanApplicationRepository -) : - ViewModel() { +) : ViewModel() { private val _reviewLoanApplicationUiState = - mutableStateOf(ReviewLoanApplicationUiState.ShowContent(ReviewLoanApplicationUiData())) - val reviewLoanApplicationUiState: State = _reviewLoanApplicationUiState + MutableStateFlow(ReviewLoanApplicationUiState.Loading) + val reviewLoanApplicationUiState: StateFlow = _reviewLoanApplicationUiState + + private var _reviewLoanApplicationUiData: MutableStateFlow = MutableStateFlow(ReviewLoanApplicationUiData()) + val reviewLoanApplicationUiData get() = _reviewLoanApplicationUiData private lateinit var loansPayload: LoansPayload - private var reviewLoanApplicationUiData: ReviewLoanApplicationUiData = - ReviewLoanApplicationUiData() fun insertData( loanState: LoanState, @@ -35,7 +37,7 @@ class ReviewLoanApplicationViewModel @Inject constructor( loanId: Long? = null, ) { this.loansPayload = loansPayload - reviewLoanApplicationUiData = ReviewLoanApplicationUiData( + _reviewLoanApplicationUiData.value = ReviewLoanApplicationUiData( loanState = loanState, loanName = loanName, accountNo = accountNo, @@ -47,28 +49,27 @@ class ReviewLoanApplicationViewModel @Inject constructor( disbursementDate = loansPayload.expectedDisbursementDate, loanId = loanId ?: 0 ) - _reviewLoanApplicationUiState.value = - ReviewLoanApplicationUiState.ShowContent(reviewLoanApplicationUiData = reviewLoanApplicationUiData) + _reviewLoanApplicationUiState.value = ReviewLoanApplicationUiState.Initial } fun submitLoan() = viewModelScope.launch(Dispatchers.IO) { _reviewLoanApplicationUiState.value = ReviewLoanApplicationUiState.Loading reviewLoanApplicationRepositoryImpl.submitLoan( - loanState = reviewLoanApplicationUiData.loanState, + loanState = reviewLoanApplicationUiData.value.loanState, loansPayload = loansPayload, - loanId = reviewLoanApplicationUiData.loanId + loanId = reviewLoanApplicationUiData.value.loanId ).catch { _reviewLoanApplicationUiState.value = ReviewLoanApplicationUiState.Error(it) }.collect { - _reviewLoanApplicationUiState.value = ReviewLoanApplicationUiState.Success(reviewLoanApplicationUiData.loanState) + _reviewLoanApplicationUiState.value = ReviewLoanApplicationUiState.Success(reviewLoanApplicationUiData.value.loanState) } } } sealed class ReviewLoanApplicationUiState { - data class ShowContent(val reviewLoanApplicationUiData: ReviewLoanApplicationUiData) : ReviewLoanApplicationUiState() + data object Initial : ReviewLoanApplicationUiState() data object Loading : ReviewLoanApplicationUiState() data class Error(val throwable: Throwable) : ReviewLoanApplicationUiState() data class Success(val loanState: LoanState) : ReviewLoanApplicationUiState()