Skip to content

Commit

Permalink
fix: loan charge display
Browse files Browse the repository at this point in the history
  • Loading branch information
Nagarjuna0033 committed Mar 1, 2025
1 parent e3c8ee2 commit 765cd4f
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ fun handleHomeNavigation(
}

HomeDestinations.RECENT_TRANSACTIONS -> navController.navigateToRecentTransaction()
HomeDestinations.CHARGES -> navController.navigateToClientChargeScreen(ChargeType.CLIENT)
HomeDestinations.CHARGES -> navController.navigateToClientChargeScreen(ChargeType.CLIENT, -1L)
HomeDestinations.THIRD_PARTY_TRANSFER -> navController.navigateToThirdPartyTransfer()
HomeDestinations.SETTINGS -> navController.navigateToSettings()
HomeDestinations.ABOUT_US -> navController.navigateToAboutUsScreen()
Expand Down
25 changes: 14 additions & 11 deletions core/ui/src/main/java/org/mifos/mobile/core/ui/utils/ImageUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object ImageUtil {
decodedBytes: ByteArray,
maxWidth: Float = DEFAULT_MAX_WIDTH,
maxHeight: Float = DEFAULT_MAX_HEIGHT,
): Bitmap {
): Bitmap? {
val options = BitmapFactory.Options().apply {
inJustDecodeBounds = true
}
Expand All @@ -43,22 +43,25 @@ object ImageUtil {
BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.size, options)
} catch (e: OutOfMemoryError) {
Log.e(this::class.java.simpleName, "OutOfMemoryError while decoding bitmap", e)
return Bitmap.createBitmap(
1,
1,
Bitmap.Config.ARGB_8888,
) // Return a 1x1 bitmap as fallback
null
}

return try {
createScaledBitmap(bmp, actualWidth, actualHeight, options)
} catch (e: OutOfMemoryError) {
Log.e(this::class.java.simpleName, "OutOfMemoryError while scaling bitmap", e)
bmp // Return the original bitmap if scaling fails
if (bmp == null) {
Log.e(this::class.java.simpleName, "Bitmap decoding failed")
}

return bmp?.let {
try {
createScaledBitmap(it, actualWidth, actualHeight, options)
} catch (e: OutOfMemoryError) {
Log.e(this::class.java.simpleName, "OutOfMemoryError while scaling bitmap", e)
it
}
}
}
}


private fun calculateActualDimensions(
options: BitmapFactory.Options,
maxWidth: Float,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.navArgument
import org.mifos.mobile.core.common.Constants.CHARGE_TYPE
import org.mifos.mobile.core.common.Constants.LOAN_ID
import org.mifos.mobile.core.model.enums.ChargeType
import org.mifos.mobile.feature.charge.screens.ClientChargeScreen

fun NavController.navigateToClientChargeScreen(
chargeType: ChargeType,
loanId: Long? = null,
) {
navigate(ClientChargeNavigation.ClientChargeScreen.passArguments(chargeType))
val route = ClientChargeNavigation.ClientChargeScreen.passArguments(chargeType, loanId)
navigate(route)
}

fun NavGraphBuilder.clientChargeNavGraph(
Expand All @@ -43,10 +46,11 @@ fun NavGraphBuilder.clientChargeScreenRoute(
) {
composable(
route = ClientChargeNavigation.ClientChargeScreen.route,
arguments = listOf(navArgument(CHARGE_TYPE) { type = NavType.StringType }),
arguments = listOf(
navArgument(CHARGE_TYPE) { type = NavType.StringType },
navArgument(LOAN_ID) { type = NavType.LongType },
),
) {
ClientChargeScreen(
navigateBack = navigateBack,
)
ClientChargeScreen(navigateBack = navigateBack)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package org.mifos.mobile.feature.charge.navigation

import org.mifos.mobile.core.common.Constants.CHARGE_TYPE
import org.mifos.mobile.core.common.Constants.LOAN_ID
import org.mifos.mobile.core.model.enums.ChargeType

// Constants for Routes
Expand All @@ -19,15 +20,20 @@ const val CLIENT_CHARGE_SCREEN_ROUTE = "client_charge_screen_route"
// Sealed class for Navigation Routes
sealed class ClientChargeNavigation(var route: String) {
data object ClientChargeBase : ClientChargeNavigation(
route = "$CLIENT_CHARGE_NAVIGATION_ROUTE_BASE/{$CHARGE_TYPE}",
route = "$CLIENT_CHARGE_NAVIGATION_ROUTE_BASE/{$CHARGE_TYPE}/${LOAN_ID}",
) {
fun passArguments(chargeType: ChargeType) =
"$CLIENT_CHARGE_NAVIGATION_ROUTE_BASE/${chargeType.name}"

fun passArguments(chargeType: ChargeType, loanId: Long) =
"$CLIENT_CHARGE_NAVIGATION_ROUTE_BASE/${chargeType.name}/$loanId"
}

data object ClientChargeScreen : ClientChargeNavigation(
route = "$CLIENT_CHARGE_SCREEN_ROUTE/{$CHARGE_TYPE}",
route = "$CLIENT_CHARGE_SCREEN_ROUTE/{$CHARGE_TYPE}/{$LOAN_ID}",
) {
fun passArguments(chargeType: ChargeType) = "$CLIENT_CHARGE_SCREEN_ROUTE/${chargeType.name}"
fun passArguments(chargeType: ChargeType, loanId: Long?): String {
return "$CLIENT_CHARGE_SCREEN_ROUTE/${chargeType.name}/$loanId"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
package org.mifos.mobile.feature.charge.screens

import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
Expand Down Expand Up @@ -59,8 +60,9 @@ internal fun ClientChargeScreen(
viewModel: ClientChargeViewModel = hiltViewModel(),
) {
val uiState by viewModel.clientChargeUiState.collectAsStateWithLifecycle()

val topBarTitle by viewModel.topBarTitleResId.collectAsStateWithLifecycle()
ClientChargeScreen(
topBarTitleResId = topBarTitle,
uiState = uiState,
navigateBack = navigateBack,
onRetry = viewModel::loadCharges,
Expand All @@ -70,14 +72,15 @@ internal fun ClientChargeScreen(

@Composable
private fun ClientChargeScreen(
@StringRes topBarTitleResId: Int,
uiState: ClientChargeState,
navigateBack: () -> Unit,
onRetry: () -> Unit,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
MifosScaffold(
topBarTitleResId = R.string.client_charges,
topBarTitleResId = topBarTitleResId,
navigateBack = navigateBack,
modifier = modifier,
content = { paddingValues ->
Expand Down Expand Up @@ -222,9 +225,10 @@ private fun ClientChargeScreenPreview(
) {
MifosMobileTheme {
ClientChargeScreen(
uiState = uiState,
navigateBack = { },
uiState = uiState,
onRetry = { },
topBarTitleResId = R.string.default_charges,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.data.repository.ClientChargeRepository
import org.mifos.mobile.core.datastore.PreferencesHelper
import org.mifos.mobile.core.model.enums.ChargeType
import org.mifos.mobile.feature.charge.utils.ClientChargeState
import org.mifos.mobile.feature.charge.utils.ClientChargeState.Loading
import org.mifos.mobile.feature.client_charge.R
import javax.inject.Inject

@HiltViewModel
Expand All @@ -37,23 +41,42 @@ internal class ClientChargeViewModel @Inject constructor(
val clientChargeUiState: StateFlow<ClientChargeState> get() = _clientChargeUiState

private val clientId = preferencesHelper.clientId

private val chargeTypeString = savedStateHandle.getStateFlow<String?>(
key = Constants.CHARGE_TYPE,
initialValue = null,
)
private val loanId = savedStateHandle.getStateFlow<Long?>(
key = Constants.LOAN_ID,
initialValue = null,
)

val chargeType: StateFlow<ChargeType?> = chargeTypeString
.map { it?.let { ChargeType.valueOf(it) } }
.stateIn(viewModelScope, SharingStarted.Lazily, null)

val topBarTitleResId: StateFlow<Int> = chargeType.map { chargeType ->
when (chargeType) {
ChargeType.CLIENT -> R.string.client_charges
ChargeType.SAVINGS -> R.string.savings_charges
ChargeType.LOAN -> R.string.loan_charges
null -> R.string.default_charges
}
}.stateIn(viewModelScope, SharingStarted.Lazily, R.string.default_charges)

init {
loadCharges()
}

fun loadCharges() {
clientId?.let { clientId ->
val chargeType = chargeTypeString.value?.let { ChargeType.valueOf(it) }
val id = loanId.value.takeIf { it != -1L } ?: clientId
Log.d("okhttp.OkHttpClient", "ID used for loading charges: $id")

chargeTypeString.value?.let { ChargeType.valueOf(it) }?.let { chargeType ->
when (chargeType) {
ChargeType.CLIENT -> loadClientCharges(clientId)
ChargeType.SAVINGS -> loadSavingsAccountCharges(clientId)
ChargeType.LOAN -> loadLoanAccountCharges(clientId)
null -> Unit
ChargeType.LOAN -> id?.let { loadLoanAccountCharges(it) }
ChargeType.SAVINGS -> id?.let { loadSavingsAccountCharges(it) }
ChargeType.CLIENT -> id?.let { loadClientCharges(it) }
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions feature/client-charge/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<resources>

<string name="client_charges">Client Charges</string>
<string name="loan_charges">Loan Charges</string>
<string name="savings_charges">Saving Charges</string>
<string name="default_charges">Default Charges</string>
<string name="error_no_charge">No charges found</string>
<string name="amount_due">Due:</string>
<string name="string_and_string">%1$s %2$s</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,20 @@ internal class HomeViewModel @Inject constructor(
}

private fun setUserProfile(image: String?) {
if (image == null) {
return
if (!image.isNullOrEmpty()) {
val decodedBytes = runCatching { Base64.decode(image, Base64.DEFAULT) }.getOrNull()
val decodedBitmap = decodedBytes?.let { ImageUtil.compressImage(it) }
val currentState = (_homeUiState.value as? HomeUiState.Success)?.homeState

if (decodedBytes != null && decodedBitmap != null && currentState != null) {
_homeUiState.value = HomeUiState.Success(currentState.copy(image = decodedBitmap))
}
}
val decodedBytes = Base64.decode(image, Base64.DEFAULT)
val decodedBitmap = ImageUtil.compressImage(decodedBytes)
var currentState = (_homeUiState.value as? HomeUiState.Success)?.homeState ?: HomeState()
currentState = currentState.copy(image = decodedBitmap)
_homeUiState.value = HomeUiState.Success(currentState)
}




/**
* Fetches the count of unread notifications
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.mifos.mobile.core.common.Network
import org.mifos.mobile.core.designsystem.components.MifosScaffold
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations
import org.mifos.mobile.core.model.enums.ChargeType
import org.mifos.mobile.core.ui.component.EmptyDataView
import org.mifos.mobile.core.ui.component.MifosProgressIndicator
import org.mifos.mobile.core.ui.component.NoInternet
Expand All @@ -38,7 +39,7 @@ internal fun LoanAccountDetailScreen(
updateLoan: (Long) -> Unit,
withdrawLoan: (Long) -> Unit,
viewLoanSummary: (Long) -> Unit,
viewCharges: () -> Unit,
viewCharges: (ChargeType, Long) -> Unit,
viewRepaymentSchedule: (Long) -> Unit,
viewTransactions: (Long) -> Unit,
viewQr: (String) -> Unit,
Expand All @@ -57,7 +58,7 @@ internal fun LoanAccountDetailScreen(
withdrawLoan = { withdrawLoan(loanId) },
retryConnection = viewModel::loadLoanAccountDetails,
viewLoanSummary = { viewLoanSummary(loanId) },
viewCharges = viewCharges,
viewCharges = { viewCharges(ChargeType.LOAN, loanId) },
modifier = modifier,
viewRepaymentSchedule = { viewRepaymentSchedule(loanId) },
viewTransactions = { viewTransactions(loanId) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ fun NavController.navigateToLoanReview(
fun NavGraphBuilder.loanNavGraph(
navController: NavController,
viewGuarantor: (Long) -> Unit,
viewCharges: (ChargeType) -> Unit,
viewCharges: (ChargeType, Long) -> Unit,
viewQr: (String) -> Unit,
makePayment: (accountId: Long, outstandingBalance: Double?, transferType: String) -> Unit,
) {
Expand All @@ -81,7 +81,7 @@ fun NavGraphBuilder.loanNavGraph(
},
withdrawLoan = { navController.navigate(LoanNavigation.LoanWithdraw.passArguments(it)) },
viewLoanSummary = { navController.navigate(LoanNavigation.LoanSummary.passArguments(it)) },
viewCharges = { viewCharges(ChargeType.LOAN) },
viewCharges = { _, loanId -> viewCharges(ChargeType.LOAN, loanId) },
viewRepaymentSchedule = {
navController.navigate(
LoanNavigation.LoanSchedule.passArguments(
Expand Down Expand Up @@ -134,7 +134,7 @@ fun NavGraphBuilder.loanDetailRoute(
updateLoan: (Long) -> Unit,
withdrawLoan: (Long) -> Unit,
viewLoanSummary: (Long) -> Unit,
viewCharges: () -> Unit,
viewCharges: (ChargeType, Long) -> Unit,
viewRepaymentSchedule: (Long) -> Unit,
viewTransactions: (Long) -> Unit,
viewQr: (String) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fun NavController.navigateToSavingsApplicationScreen() {
fun NavGraphBuilder.savingsNavGraph(
navController: NavController,
viewQrCode: (String) -> Unit,
viewCharges: (ChargeType) -> Unit,
viewCharges: (ChargeType, Long) -> Unit,
reviewTransfer: (ReviewTransferPayload, TransferType) -> Unit,
callHelpline: () -> Unit,
) {
Expand Down Expand Up @@ -93,7 +93,7 @@ fun NavGraphBuilder.savingsNavGraph(
),
)
},
viewCharges = { viewCharges(ChargeType.SAVINGS) },
viewCharges = { _, savingsId -> viewCharges(ChargeType.SAVINGS, savingsId) },
viewQrCode = viewQrCode,
viewTransaction = {
navController.navigate(
Expand Down Expand Up @@ -132,7 +132,7 @@ fun NavGraphBuilder.savingsDetailRoute(
withdrawSavingsAccount: (Long) -> Unit,
makeTransfer: (Long) -> Unit,
viewTransaction: (Long) -> Unit,
viewCharges: () -> Unit,
viewCharges: (ChargeType, Long) -> Unit,
viewQrCode: (String) -> Unit,
callUs: () -> Unit,
deposit: (Long) -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.mifos.mobile.core.designsystem.components.MifosScaffold
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations
import org.mifos.mobile.core.model.enums.ChargeType
import org.mifos.mobile.core.ui.component.EmptyDataView
import org.mifos.mobile.core.ui.component.MifosErrorComponent
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
Expand All @@ -33,7 +34,7 @@ internal fun SavingsAccountDetailScreen(
withdrawSavingsAccount: (Long) -> Unit,
makeTransfer: (Long) -> Unit,
viewTransaction: (Long) -> Unit,
viewCharges: () -> Unit,
viewCharges: (ChargeType, Long) -> Unit,
viewQrCode: (String) -> Unit,
callUs: () -> Unit,
deposit: (Long) -> Unit,
Expand All @@ -51,7 +52,7 @@ internal fun SavingsAccountDetailScreen(
withdrawSavingsAccount = { withdrawSavingsAccount(savingsId) },
makeTransfer = { makeTransfer(savingsId) },
viewTransaction = { viewTransaction(savingsId) },
viewCharges = viewCharges,
viewCharges = { viewCharges(ChargeType.SAVINGS, savingsId) },
viewQrCode = { viewQrCode(viewModel.getQrString(it)) },
callUs = callUs,
deposit = { deposit(savingsId) },
Expand Down

0 comments on commit 765cd4f

Please sign in to comment.