diff --git a/core/designsystem/src/main/kotlin/org/mifos/mobile/core/designsystem/components/MifosButton.kt b/core/designsystem/src/main/kotlin/org/mifos/mobile/core/designsystem/components/MifosButton.kt
index c68857daa..2871e2a90 100644
--- a/core/designsystem/src/main/kotlin/org/mifos/mobile/core/designsystem/components/MifosButton.kt
+++ b/core/designsystem/src/main/kotlin/org/mifos/mobile/core/designsystem/components/MifosButton.kt
@@ -20,6 +20,7 @@ import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.material3.Icon
+import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
@@ -144,6 +145,21 @@ fun MifosOutlinedTextButton(
)
}
+@Composable
+fun MifosOutlinedButton(
+ textResId: Int,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ OutlinedButton(
+ onClick = onClick,
+ modifier = modifier,
+ content = {
+ Text(text = stringResource(id = textResId))
+ },
+ )
+}
+
@Composable
fun MifosIconTextButton(
text: String,
diff --git a/feature/savings/build.gradle.kts b/feature/savings/build.gradle.kts
index ad347eee2..9f7d19114 100644
--- a/feature/savings/build.gradle.kts
+++ b/feature/savings/build.gradle.kts
@@ -1,3 +1,12 @@
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
plugins {
alias(libs.plugins.mifos.android.feature)
alias(libs.plugins.mifos.android.library.compose)
diff --git a/feature/savings/src/main/AndroidManifest.xml b/feature/savings/src/main/AndroidManifest.xml
index a5918e68a..1f9b243f0 100644
--- a/feature/savings/src/main/AndroidManifest.xml
+++ b/feature/savings/src/main/AndroidManifest.xml
@@ -1,4 +1,13 @@
+
\ No newline at end of file
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavGraph.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavGraph.kt
index a9faeb615..e0a52e76b 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavGraph.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavGraph.kt
@@ -1,3 +1,12 @@
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
package org.mifos.mobile.feature.savings.navigation
import androidx.navigation.NavController
@@ -13,20 +22,28 @@ import org.mifos.mobile.core.common.Constants.SAVINGS_ID
import org.mifos.mobile.core.common.Constants.TRANSFER_PAY_FROM
import org.mifos.mobile.core.common.Constants.TRANSFER_PAY_TO
import org.mifos.mobile.core.common.Constants.TRANSFER_TYPE
-import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations
import org.mifos.mobile.core.model.entity.payload.ReviewTransferPayload
import org.mifos.mobile.core.model.enums.ChargeType
-import org.mifos.mobile.core.model.enums.LoanState
import org.mifos.mobile.core.model.enums.SavingsAccountState
import org.mifos.mobile.core.model.enums.TransferType
-import org.mifos.mobile.feature.savings.savings_account.SavingsAccountDetailScreen
-import org.mifos.mobile.feature.savings.savings_account_application.SavingsAccountApplicationScreen
-import org.mifos.mobile.feature.savings.savings_account_transaction.SavingsAccountTransactionScreen
-import org.mifos.mobile.feature.savings.savings_account_withdraw.SavingsAccountWithdrawScreen
-import org.mifos.mobile.feature.savings.savings_make_transfer.SavingsMakeTransferScreen
+import org.mifos.mobile.feature.savings.savingsAccount.SavingsAccountDetailScreen
+import org.mifos.mobile.feature.savings.savingsAccountApplication.SavingsAccountApplicationScreen
+import org.mifos.mobile.feature.savings.savingsAccountTransaction.SavingsAccountTransactionScreen
+import org.mifos.mobile.feature.savings.savingsAccountWithdraw.SavingsAccountWithdrawScreen
+import org.mifos.mobile.feature.savings.savingsMakeTransfer.SavingsMakeTransferScreen
-fun NavController.navigateToSavingsMakeTransfer(accountId: Long, outstandingBalance: Double? = null, transferType: String) {
- navigate(SavingsNavigation.SavingsMakeTransfer.passArguments(accountId, (outstandingBalance ?: 0.0).toString(), transferType))
+fun NavController.navigateToSavingsMakeTransfer(
+ accountId: Long,
+ outstandingBalance: Double? = null,
+ transferType: String,
+) {
+ navigate(
+ SavingsNavigation.SavingsMakeTransfer.passArguments(
+ accountId,
+ (outstandingBalance ?: 0.0).toString(),
+ transferType,
+ ),
+ )
}
fun NavController.navigateToSavingsDetailScreen(savingsId: Long) {
@@ -37,8 +54,8 @@ fun NavController.navigateToSavingsApplicationScreen() {
navigate(
SavingsNavigation.SavingsApplication.passArguments(
savingsId = -1L,
- savingsAccountState = SavingsAccountState.CREATE
- )
+ savingsAccountState = SavingsAccountState.CREATE,
+ ),
)
}
@@ -47,7 +64,7 @@ fun NavGraphBuilder.savingsNavGraph(
viewQrCode: (String) -> Unit,
viewCharges: (ChargeType) -> Unit,
reviewTransfer: (ReviewTransferPayload, TransferType) -> Unit,
- callHelpline: () -> Unit
+ callHelpline: () -> Unit,
) {
navigation(
startDestination = SavingsNavigation.SavingsDetail.route,
@@ -55,14 +72,39 @@ fun NavGraphBuilder.savingsNavGraph(
) {
savingsDetailRoute(
callUs = callHelpline,
- deposit = { navController.navigateToSavingsMakeTransfer(accountId = it, transferType = TRANSFER_PAY_TO) },
- makeTransfer = { navController.navigateToSavingsMakeTransfer(accountId = it, transferType = TRANSFER_PAY_FROM) },
+ deposit = {
+ navController.navigateToSavingsMakeTransfer(
+ accountId = it,
+ transferType = TRANSFER_PAY_TO,
+ )
+ },
+ makeTransfer = {
+ navController.navigateToSavingsMakeTransfer(
+ accountId = it,
+ transferType = TRANSFER_PAY_FROM,
+ )
+ },
navigateBack = navController::popBackStack,
- updateSavingsAccount = { navController.navigate(SavingsNavigation.SavingsApplication.passArguments(savingsId = it, savingsAccountState = SavingsAccountState.UPDATE)) },
+ updateSavingsAccount = {
+ navController.navigate(
+ SavingsNavigation.SavingsApplication.passArguments(
+ savingsId = it,
+ savingsAccountState = SavingsAccountState.UPDATE,
+ ),
+ )
+ },
viewCharges = { viewCharges(ChargeType.SAVINGS) },
viewQrCode = viewQrCode,
- viewTransaction = { navController.navigate(SavingsNavigation.SavingsTransaction.passArguments(it)) },
- withdrawSavingsAccount = { navController.navigate(SavingsNavigation.SavingsWithdraw.passArguments(it)) }
+ viewTransaction = {
+ navController.navigate(
+ SavingsNavigation.SavingsTransaction.passArguments(it),
+ )
+ },
+ withdrawSavingsAccount = {
+ navController.navigate(
+ SavingsNavigation.SavingsWithdraw.passArguments(it),
+ )
+ },
)
savingsApplication(
@@ -79,7 +121,7 @@ fun NavGraphBuilder.savingsNavGraph(
savingsMakeTransfer(
navigateBack = navController::popBackStack,
- reviewTransfer = reviewTransfer
+ reviewTransfer = reviewTransfer,
)
}
}
@@ -93,13 +135,13 @@ fun NavGraphBuilder.savingsDetailRoute(
viewCharges: () -> Unit,
viewQrCode: (String) -> Unit,
callUs: () -> Unit,
- deposit: (Long) -> Unit
+ deposit: (Long) -> Unit,
) {
composable(
route = SavingsNavigation.SavingsDetail.route,
arguments = listOf(
navArgument(name = SAVINGS_ID) { type = NavType.LongType },
- )
+ ),
) {
SavingsAccountDetailScreen(
navigateBack = navigateBack,
@@ -116,14 +158,16 @@ fun NavGraphBuilder.savingsDetailRoute(
}
fun NavGraphBuilder.savingsApplication(
- navigateBack: () -> Unit
+ navigateBack: () -> Unit,
) {
composable(
route = SavingsNavigation.SavingsApplication.route,
arguments = listOf(
navArgument(name = SAVINGS_ID) { type = NavType.LongType },
- navArgument(Constants.SAVINGS_ACCOUNT_STATE) { type = NavType.EnumType(SavingsAccountState::class.java) },
- )
+ navArgument(Constants.SAVINGS_ACCOUNT_STATE) {
+ type = NavType.EnumType(SavingsAccountState::class.java)
+ },
+ ),
) {
SavingsAccountApplicationScreen(
navigateBack = navigateBack,
@@ -136,7 +180,7 @@ fun NavGraphBuilder.savingsTransaction(
) {
composable(
route = SavingsNavigation.SavingsTransaction.route,
- arguments = listOf(navArgument(name = SAVINGS_ID) { type = NavType.LongType })
+ arguments = listOf(navArgument(name = SAVINGS_ID) { type = NavType.LongType }),
) {
SavingsAccountTransactionScreen(
navigateBack = navigateBack,
@@ -149,7 +193,7 @@ fun NavGraphBuilder.savingsWithdraw(
) {
composable(
route = SavingsNavigation.SavingsWithdraw.route,
- arguments = listOf(navArgument(SAVINGS_ID) { type = NavType.LongType })
+ arguments = listOf(navArgument(SAVINGS_ID) { type = NavType.LongType }),
) {
SavingsAccountWithdrawScreen(
navigateBack = { navigateBack() },
@@ -159,7 +203,7 @@ fun NavGraphBuilder.savingsWithdraw(
fun NavGraphBuilder.savingsMakeTransfer(
navigateBack: () -> Unit,
- reviewTransfer: (ReviewTransferPayload, TransferType) -> Unit
+ reviewTransfer: (ReviewTransferPayload, TransferType) -> Unit,
) {
composable(
route = SavingsNavigation.SavingsMakeTransfer.route,
@@ -171,12 +215,12 @@ fun NavGraphBuilder.savingsMakeTransfer(
defaultValue = null
},
navArgument(name = TRANSFER_TYPE) { type = NavType.StringType },
- )
+ ),
) {
SavingsMakeTransferScreen(
navigateBack = navigateBack,
onCancelledClicked = navigateBack,
- reviewTransfer = reviewTransfer
+ reviewTransfer = reviewTransfer,
)
}
}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavigation.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavigation.kt
index d5c6470f7..d7ee0a10c 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavigation.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/navigation/SavingsNavigation.kt
@@ -1,12 +1,19 @@
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
package org.mifos.mobile.feature.savings.navigation
-import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.common.Constants.ACCOUNT_ID
import org.mifos.mobile.core.common.Constants.OUTSTANDING_BALANCE
import org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNT_STATE
import org.mifos.mobile.core.common.Constants.SAVINGS_ID
import org.mifos.mobile.core.common.Constants.TRANSFER_TYPE
-import org.mifos.mobile.core.model.enums.LoanState
import org.mifos.mobile.core.model.enums.SavingsAccountState
const val SAVINGS_NAVIGATION_ROUTE_BASE = "savings_route"
@@ -18,22 +25,26 @@ const val SAVINGS_MAKE_TRANSFER_SCREEN_ROUTE = "savings_make_transfer_screen_rou
sealed class SavingsNavigation(val route: String) {
data object SavingsBase : SavingsNavigation(
- route = SAVINGS_NAVIGATION_ROUTE_BASE
+ route = SAVINGS_NAVIGATION_ROUTE_BASE,
)
data object SavingsDetail : SavingsNavigation(
- route = "$SAVINGS_DETAIL_SCREEN_ROUTE/{$SAVINGS_ID}"
+ route = "$SAVINGS_DETAIL_SCREEN_ROUTE/{$SAVINGS_ID}",
) {
fun passArguments(savingsId: Long) = "$SAVINGS_DETAIL_SCREEN_ROUTE/$savingsId"
}
data object SavingsApplication : SavingsNavigation(
- route = "$SAVINGS_APPLICATION_SCREEN_ROUTE/{${SAVINGS_ID}}/{${SAVINGS_ACCOUNT_STATE}}") {
- fun passArguments(savingsId: Long, savingsAccountState: SavingsAccountState) = "$SAVINGS_APPLICATION_SCREEN_ROUTE/${savingsId}/${savingsAccountState}"
+ route = "$SAVINGS_APPLICATION_SCREEN_ROUTE/{${SAVINGS_ID}}/{${SAVINGS_ACCOUNT_STATE}}",
+ ) {
+ fun passArguments(
+ savingsId: Long,
+ savingsAccountState: SavingsAccountState,
+ ) = "$SAVINGS_APPLICATION_SCREEN_ROUTE/$savingsId/$savingsAccountState"
}
data object SavingsTransaction : SavingsNavigation(
- route = "$SAVINGS_TRANSACTION_SCREEN_ROUTE/{${SAVINGS_ID}}"
+ route = "$SAVINGS_TRANSACTION_SCREEN_ROUTE/{${SAVINGS_ID}}",
) {
fun passArguments(savingsId: Long): String {
return "$SAVINGS_TRANSACTION_SCREEN_ROUTE/$savingsId"
@@ -41,7 +52,7 @@ sealed class SavingsNavigation(val route: String) {
}
data object SavingsWithdraw : SavingsNavigation(
- route = "$SAVINGS_WITHDRAW_SCREEN_ROUTE/{${SAVINGS_ID}}"
+ route = "$SAVINGS_WITHDRAW_SCREEN_ROUTE/{${SAVINGS_ID}}",
) {
fun passArguments(savingsId: Long): String {
return "$SAVINGS_WITHDRAW_SCREEN_ROUTE/$savingsId"
@@ -49,9 +60,13 @@ sealed class SavingsNavigation(val route: String) {
}
data object SavingsMakeTransfer : SavingsNavigation(
- route = "$SAVINGS_MAKE_TRANSFER_SCREEN_ROUTE/{$ACCOUNT_ID}/{$OUTSTANDING_BALANCE}/{$TRANSFER_TYPE}"
+ route = "$SAVINGS_MAKE_TRANSFER_SCREEN_ROUTE/{$ACCOUNT_ID}/{$OUTSTANDING_BALANCE}/{$TRANSFER_TYPE}",
) {
- fun passArguments(accountId: Long, outstandingBalance: String? = null, transferType: String): String {
+ fun passArguments(
+ accountId: Long,
+ outstandingBalance: String? = null,
+ transferType: String,
+ ): String {
return "$SAVINGS_MAKE_TRANSFER_SCREEN_ROUTE/$accountId/$outstandingBalance/$transferType"
}
}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingAccountsDetailViewModel.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingAccountsDetailViewModel.kt
similarity index 76%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingAccountsDetailViewModel.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingAccountsDetailViewModel.kt
index ac2fe09dc..b21a37fe9 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingAccountsDetailViewModel.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingAccountsDetailViewModel.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccount
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.SavedStateHandle
@@ -26,18 +35,20 @@ import org.mifos.mobile.feature.savings.R
import javax.inject.Inject
@HiltViewModel
-class SavingAccountsDetailViewModel @Inject constructor(
+internal class SavingAccountsDetailViewModel @Inject constructor(
private val savingsAccountRepositoryImp: SavingsAccountRepository,
savedStateHandle: SavedStateHandle,
- private var preferencesHelper: PreferencesHelper
+ private var preferencesHelper: PreferencesHelper,
) : ViewModel() {
- val savingsId = savedStateHandle.getStateFlow(key = Constants.SAVINGS_ID, initialValue = null)
+ val savingsId =
+ savedStateHandle.getStateFlow(key = Constants.SAVINGS_ID, initialValue = null)
val savingAccountsDetailUiState = savingsId
.flatMapLatest {
savingsAccountRepositoryImp.getSavingsWithAssociations(
- savingsId.value, Constants.TRANSACTIONS,
+ savingsId.value,
+ Constants.TRANSACTIONS,
)
}
.asResult()
@@ -50,7 +61,7 @@ class SavingAccountsDetailViewModel @Inject constructor(
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
- initialValue = SavingsAccountDetailUiState.Loading
+ initialValue = SavingsAccountDetailUiState.Loading,
)
fun getQrString(savingsWithAssociations: SavingsWithAssociations?): String {
@@ -62,13 +73,13 @@ class SavingAccountsDetailViewModel @Inject constructor(
}
}
-sealed class SavingsAccountDetailUiState {
+internal sealed class SavingsAccountDetailUiState {
data object Loading : SavingsAccountDetailUiState()
data object Error : SavingsAccountDetailUiState()
data class Success(val savingAccount: SavingsWithAssociations) : SavingsAccountDetailUiState()
}
-fun Status.getStatusColorAndText(): Pair {
+internal fun Status.getStatusColorAndText(): Pair {
return when {
this.active == true -> Pair(DepositGreen, R.string.active)
this.approved == true -> Pair(Blue, R.string.need_approval)
@@ -77,5 +88,3 @@ fun Status.getStatusColorAndText(): Pair {
else -> Pair(Color.Black, R.string.closed)
}
}
-
-
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailContent.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailContent.kt
similarity index 79%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailContent.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailContent.kt
index cdf2b60fc..3d93699ea 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailContent.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailContent.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccount
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -15,7 +24,6 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -27,47 +35,49 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
+import org.mifos.mobile.core.common.utils.CurrencyUtil
+import org.mifos.mobile.core.common.utils.DateHelper
+import org.mifos.mobile.core.common.utils.SymbolsUtils
+import org.mifos.mobile.core.designsystem.components.MifosOutlinedButton
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations
import org.mifos.mobile.core.model.entity.accounts.savings.Status
import org.mifos.mobile.core.ui.component.MifosLinkText
import org.mifos.mobile.core.ui.component.MifosTextTitleDescDoubleLine
import org.mifos.mobile.core.ui.component.MonitorListItemWithIcon
-import org.mifos.mobile.core.common.utils.CurrencyUtil
-import org.mifos.mobile.core.common.utils.DateHelper
-import org.mifos.mobile.core.common.utils.SymbolsUtils
import org.mifos.mobile.feature.savings.R
@Composable
-fun SavingsAccountDetailContent(
+internal fun SavingsAccountDetailContent(
savingsAccount: SavingsWithAssociations,
deposit: () -> Unit,
makeTransfer: () -> Unit,
viewTransaction: () -> Unit,
viewCharges: () -> Unit,
viewQrCode: (SavingsWithAssociations) -> Unit,
- callUs: () -> Unit
+ callUs: () -> Unit,
+ modifier: Modifier = Modifier,
) {
val scrollState = rememberScrollState()
val currencySymbol = savingsAccount.currency?.displaySymbol ?: "$"
Column(
- modifier = Modifier
+ modifier = modifier
.fillMaxWidth()
.verticalScroll(scrollState)
- .padding(16.dp)
+ .padding(16.dp),
) {
AccountDetailsCard(
- makeTransfer = makeTransfer,
- deposit = deposit,
+ currencySymbol = currencySymbol,
savingsAccount = savingsAccount,
- currencySymbol = currencySymbol
+ deposit = deposit,
+ makeTransfer = makeTransfer,
)
Spacer(modifier = Modifier.height(20.dp))
LastTransactionCard(
savingsWithAssociations = savingsAccount,
- currencySymbol = currencySymbol
+ currencySymbol = currencySymbol,
)
Spacer(modifier = Modifier.height(20.dp))
@@ -75,7 +85,7 @@ fun SavingsAccountDetailContent(
SavingsMonitorComponent(
viewTransaction = viewTransaction,
viewCharges = viewCharges,
- viewQrCode = { viewQrCode.invoke(savingsAccount) }
+ viewQrCode = { viewQrCode.invoke(savingsAccount) },
)
Spacer(modifier = Modifier.height(20.dp))
@@ -84,29 +94,33 @@ fun SavingsAccountDetailContent(
Text(
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface,
- text = stringResource(id = R.string.need_help)
+ text = stringResource(id = R.string.need_help),
)
Spacer(modifier = Modifier.width(5.dp))
MifosLinkText(
text = stringResource(id = R.string.help_line_number),
- onClick = { callUs.invoke() },
- isUnderlined = false
+ onClick = callUs,
+ isUnderlined = false,
)
}
}
}
@Composable
-fun AccountDetailsCard(
- modifier: Modifier = Modifier,
+private fun AccountDetailsCard(
+ currencySymbol: String,
savingsAccount: SavingsWithAssociations,
deposit: () -> Unit,
makeTransfer: () -> Unit,
- currencySymbol: String
+ modifier: Modifier = Modifier,
) {
val context = LocalContext.current
+
OutlinedCard(modifier = modifier) {
- Column(modifier = Modifier.padding(14.dp)) {
+ Column(
+ modifier = Modifier
+ .padding(14.dp),
+ ) {
MifosTextTitleDescDoubleLine(
title = stringResource(id = R.string.account_balance),
description = stringResource(
@@ -114,17 +128,19 @@ fun AccountDetailsCard(
currencySymbol,
CurrencyUtil.formatCurrency(
context = context,
- amt = savingsAccount.summary?.accountBalance ?: 0.0
- )
+ amt = savingsAccount.summary?.accountBalance ?: 0.0,
+ ),
+ ),
+ descriptionStyle = MaterialTheme.typography.bodyLarge.copy(
+ fontWeight = FontWeight.Bold,
),
- descriptionStyle = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold)
)
Spacer(modifier = Modifier.height(8.dp))
StatusField(
title = stringResource(id = R.string.account_status),
- accountStatus = savingsAccount.status ?: Status()
+ accountStatus = savingsAccount.status ?: Status(),
)
Spacer(modifier = Modifier.height(8.dp))
@@ -142,9 +158,9 @@ fun AccountDetailsCard(
description = stringResource(
id = R.string.double_and_string,
savingsAccount.getNominalAnnualInterestRate(),
- SymbolsUtils.PERCENT
+ SymbolsUtils.PERCENT,
),
- descriptionStyle = MaterialTheme.typography.bodyLarge
+ descriptionStyle = MaterialTheme.typography.bodyLarge,
)
Spacer(modifier = Modifier.height(8.dp))
@@ -158,12 +174,12 @@ fun AccountDetailsCard(
CurrencyUtil.formatCurrency(
context = context,
amt = savingsAccount.summary?.totalDeposits ?: 0.0,
- )
+ ),
)
} else {
stringResource(id = R.string.not_available)
},
- descriptionStyle = MaterialTheme.typography.bodyLarge
+ descriptionStyle = MaterialTheme.typography.bodyLarge,
)
Spacer(modifier = Modifier.height(8.dp))
@@ -173,7 +189,8 @@ fun AccountDetailsCard(
descriptionStyle = MaterialTheme.typography.bodyLarge,
description = if (savingsAccount.summary?.totalDeposits != null) {
stringResource(
- id = R.string.string_and_string, currencySymbol,
+ id = R.string.string_and_string,
+ currencySymbol,
CurrencyUtil.formatCurrency(
context = context,
amt = savingsAccount.summary?.totalWithdrawals ?: 0.0,
@@ -181,35 +198,44 @@ fun AccountDetailsCard(
)
} else {
stringResource(id = R.string.no_withdrawals)
- }
+ },
)
Spacer(modifier = Modifier.height(8.dp))
- Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
- OutlinedButton(onClick = {
- if(savingsAccount.status?.active == true) {
- deposit()
- }
- }) { Text(text = stringResource(id = R.string.deposit)) }
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.End,
+ ) {
+ MifosOutlinedButton(
+ textResId = R.string.deposit,
+ onClick = {
+ if (savingsAccount.status?.active == true) {
+ deposit()
+ }
+ },
+ )
Spacer(modifier = Modifier.width(8.dp))
- OutlinedButton(onClick = {
- if(savingsAccount.status?.active == true) {
- makeTransfer()
- }
- }) { Text(text = stringResource(id = R.string.make_transfer)) }
+ MifosOutlinedButton(
+ textResId = R.string.make_transfer,
+ onClick = {
+ if (savingsAccount.status?.active == true) {
+ makeTransfer()
+ }
+ },
+ )
}
}
}
}
@Composable
-fun LastTransactionCard(
+private fun LastTransactionCard(
savingsWithAssociations: SavingsWithAssociations,
currencySymbol: String,
- modifier: Modifier = Modifier
+ modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val isTransactionEmpty = savingsWithAssociations.transactions.isEmpty()
@@ -219,7 +245,7 @@ fun LastTransactionCard(
text = stringResource(id = R.string.last_trans),
style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold),
color = MaterialTheme.colorScheme.onSurface,
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(8.dp))
@@ -235,9 +261,9 @@ fun LastTransactionCard(
stringResource(
id = R.string.string_and_double,
currencySymbol,
- savingsWithAssociations.transactions[0].amount ?: 0.0
+ savingsWithAssociations.transactions[0].amount ?: 0.0,
)
- }
+ },
)
if (!isTransactionEmpty) {
@@ -247,7 +273,7 @@ fun LastTransactionCard(
descriptionStyle = MaterialTheme.typography.bodyLarge,
description = DateHelper.getDateAsString(
savingsWithAssociations.lastActiveTransactionDate,
- )
+ ),
)
}
@@ -257,12 +283,13 @@ fun LastTransactionCard(
title = stringResource(id = R.string.min_required_balance),
descriptionStyle = MaterialTheme.typography.bodyLarge,
description = stringResource(
- id = R.string.string_and_string, currencySymbol,
+ id = R.string.string_and_string,
+ currencySymbol,
CurrencyUtil.formatCurrency(
context = context,
amt = savingsWithAssociations.minRequiredOpeningBalance ?: 0.0,
),
- )
+ ),
)
}
}
@@ -271,11 +298,11 @@ fun LastTransactionCard(
}
@Composable
-fun SavingsMonitorComponent(
- modifier: Modifier = Modifier,
+private fun SavingsMonitorComponent(
viewTransaction: () -> Unit,
viewCharges: () -> Unit,
viewQrCode: () -> Unit,
+ modifier: Modifier = Modifier,
) {
Column(modifier = modifier.fillMaxWidth()) {
Text(
@@ -291,37 +318,38 @@ fun SavingsMonitorComponent(
titleId = R.string.transactions,
subTitleId = R.string.view_transactions,
iconId = R.drawable.ic_compare_arrows_black_24dp,
- onClick = viewTransaction
+ onClick = viewTransaction,
)
MonitorListItemWithIcon(
titleId = R.string.savings_charges,
subTitleId = R.string.view_charges,
iconId = R.drawable.ic_charges,
- onClick = viewCharges
+ onClick = viewCharges,
)
MonitorListItemWithIcon(
titleId = R.string.qr_code,
subTitleId = R.string.view_qr_code,
iconId = R.drawable.ic_qrcode_scan,
- onClick = viewQrCode
+ onClick = viewQrCode,
)
}
}
@Composable
-fun StatusField(
+private fun StatusField(
title: String,
- accountStatus: Status
+ accountStatus: Status,
+ modifier: Modifier = Modifier,
) {
val (color, textResId) = accountStatus.getStatusColorAndText()
- Column(modifier = Modifier.fillMaxWidth()) {
+ Column(modifier = modifier.fillMaxWidth()) {
Text(
text = title,
style = MaterialTheme.typography.labelMedium,
modifier = Modifier
.alpha(0.7f)
- .fillMaxWidth()
+ .fillMaxWidth(),
)
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -329,14 +357,14 @@ fun StatusField(
modifier = Modifier
.clip(CircleShape)
.background(color = color)
- .size(15.dp)
+ .size(15.dp),
)
Spacer(modifier = Modifier.width(4.dp))
Text(
text = stringResource(id = textResId),
style = MaterialTheme.typography.bodyLarge,
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
)
}
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailScreen.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailScreen.kt
similarity index 64%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailScreen.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailScreen.kt
index 73116c258..c4424cf55 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailScreen.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailScreen.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccount
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -6,7 +15,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.mifos.mobile.core.designsystem.components.MifosScaffold
@@ -15,11 +23,11 @@ import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociatio
import org.mifos.mobile.core.ui.component.EmptyDataView
import org.mifos.mobile.core.ui.component.MifosErrorComponent
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
@Composable
-fun SavingsAccountDetailScreen(
- viewModel: SavingAccountsDetailViewModel = hiltViewModel(),
+internal fun SavingsAccountDetailScreen(
navigateBack: () -> Unit,
updateSavingsAccount: (Long) -> Unit,
withdrawSavingsAccount: (Long) -> Unit,
@@ -28,27 +36,30 @@ fun SavingsAccountDetailScreen(
viewCharges: () -> Unit,
viewQrCode: (String) -> Unit,
callUs: () -> Unit,
- deposit: (Long) -> Unit
+ deposit: (Long) -> Unit,
+ modifier: Modifier = Modifier,
+ viewModel: SavingAccountsDetailViewModel = hiltViewModel(),
) {
val uiState by viewModel.savingAccountsDetailUiState.collectAsStateWithLifecycle()
+ val savingsId = viewModel.savingsId.collectAsStateWithLifecycle().value ?: -1L
SavingsAccountDetailScreen(
uiState = uiState,
navigateBack = navigateBack,
- updateSavingsAccount = { updateSavingsAccount(viewModel.savingsId.value ?: -1L) },
- withdrawSavingsAccount = { withdrawSavingsAccount(viewModel.savingsId.value ?: -1L) },
- makeTransfer = { makeTransfer(viewModel.savingsId.value ?: -1L) },
- viewTransaction = { viewTransaction(viewModel.savingsId.value ?: -1L) },
+ modifier = modifier,
+ updateSavingsAccount = { updateSavingsAccount(savingsId) },
+ withdrawSavingsAccount = { withdrawSavingsAccount(savingsId) },
+ makeTransfer = { makeTransfer(savingsId) },
+ viewTransaction = { viewTransaction(savingsId) },
viewCharges = viewCharges,
viewQrCode = { viewQrCode(viewModel.getQrString(it)) },
callUs = callUs,
- deposit = { deposit(viewModel.savingsId.value ?: -1L) },
+ deposit = { deposit(savingsId) },
)
}
-
@Composable
-fun SavingsAccountDetailScreen(
+private fun SavingsAccountDetailScreen(
uiState: SavingsAccountDetailUiState,
navigateBack: () -> Unit,
updateSavingsAccount: () -> Unit,
@@ -59,32 +70,30 @@ fun SavingsAccountDetailScreen(
viewQrCode: (SavingsWithAssociations) -> Unit,
callUs: () -> Unit,
deposit: () -> Unit,
+ modifier: Modifier = Modifier,
) {
MifosScaffold(
topBar = {
SavingsAccountDetailTopBar(
navigateBack = navigateBack,
updateSavingsAccount = updateSavingsAccount,
- withdrawSavingsAccount = withdrawSavingsAccount
+ withdrawSavingsAccount = withdrawSavingsAccount,
)
- }
+ },
+ modifier = modifier,
) {
Box(modifier = Modifier.padding(it)) {
when (uiState) {
- is SavingsAccountDetailUiState.Error -> {
- MifosErrorComponent()
- }
+ is SavingsAccountDetailUiState.Error -> MifosErrorComponent()
- is SavingsAccountDetailUiState.Loading -> {
- MifosProgressIndicatorOverlay()
- }
+ is SavingsAccountDetailUiState.Loading -> MifosProgressIndicatorOverlay()
is SavingsAccountDetailUiState.Success -> {
if (uiState.savingAccount.status?.submittedAndPendingApproval == true) {
EmptyDataView(
modifier = Modifier.fillMaxSize(),
icon = R.drawable.ic_assignment_turned_in_black_24dp,
- error = R.string.approval_pending
+ error = R.string.approval_pending,
)
} else {
SavingsAccountDetailContent(
@@ -94,7 +103,7 @@ fun SavingsAccountDetailScreen(
viewTransaction = viewTransaction,
viewQrCode = viewQrCode,
callUs = callUs,
- deposit = deposit
+ deposit = deposit,
)
}
}
@@ -103,13 +112,21 @@ fun SavingsAccountDetailScreen(
}
}
-@Preview(showSystemUi = true)
+@DevicePreviews
@Composable
-fun SavingsAccountDetailScreenPreview() {
+private fun SavingsAccountDetailScreenPreview() {
MifosMobileTheme {
SavingsAccountDetailScreen(
uiState = SavingsAccountDetailUiState.Loading,
- {}, {}, {}, {}, {}, {}, {}, {}, {}
+ navigateBack = {},
+ updateSavingsAccount = {},
+ withdrawSavingsAccount = {},
+ makeTransfer = {},
+ viewTransaction = {},
+ viewCharges = {},
+ viewQrCode = {},
+ callUs = {},
+ deposit = {},
)
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailTopBar.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailTopBar.kt
similarity index 63%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailTopBar.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailTopBar.kt
index 072051417..3a6616432 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account/SavingsAccountDetailTopBar.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccount/SavingsAccountDetailTopBar.kt
@@ -1,8 +1,14 @@
-package org.mifos.mobile.feature.savings.savings_account
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccount
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.ArrowBack
-import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -19,70 +25,76 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.tooling.preview.Preview
+import org.mifos.mobile.core.designsystem.icons.MifosIcons
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun SavingsAccountDetailTopBar(
+internal fun SavingsAccountDetailTopBar(
navigateBack: () -> Unit,
updateSavingsAccount: () -> Unit,
- withdrawSavingsAccount: () -> Unit
+ withdrawSavingsAccount: () -> Unit,
+ modifier: Modifier = Modifier,
) {
var showMenu by remember { mutableStateOf(false) }
TopAppBar(
- modifier = Modifier,
+ modifier = modifier,
title = { Text(text = stringResource(id = R.string.saving_account_details)) },
navigationIcon = {
IconButton(
- onClick = { navigateBack.invoke() }
+ onClick = { navigateBack.invoke() },
) {
Icon(
- imageVector = Icons.Filled.ArrowBack,
+ imageVector = MifosIcons.ArrowBack,
contentDescription = "Back Arrow",
- tint = MaterialTheme.colorScheme.onSurface
+ tint = MaterialTheme.colorScheme.onSurface,
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
- containerColor = MaterialTheme.colorScheme.background
+ containerColor = MaterialTheme.colorScheme.background,
),
actions = {
IconButton(onClick = { showMenu = !showMenu }) {
Icon(
- imageVector = Icons.Filled.MoreVert,
+ imageVector = MifosIcons.MoreVert,
contentDescription = "Menu",
- tint = MaterialTheme.colorScheme.onSurface
+ tint = MaterialTheme.colorScheme.onSurface,
)
}
DropdownMenu(
expanded = showMenu,
- onDismissRequest = { showMenu = false }
+ onDismissRequest = { showMenu = false },
) {
DropdownMenuItem(
text = {
Text(text = stringResource(id = R.string.update_savings_account))
},
- onClick = { updateSavingsAccount.invoke() }
+ onClick = { updateSavingsAccount.invoke() },
)
DropdownMenuItem(
text = {
Text(text = stringResource(id = R.string.withdraw_savings_account))
},
- onClick = { withdrawSavingsAccount.invoke() }
+ onClick = { withdrawSavingsAccount.invoke() },
)
}
- }
+ },
)
}
-@Preview
+@DevicePreviews
@Composable
-fun SavingsAccountDetailTopBarPreview() {
+private fun SavingsAccountDetailTopBarPreview() {
MifosMobileTheme {
- SavingsAccountDetailTopBar({}, {}, {})
+ SavingsAccountDetailTopBar(
+ navigateBack = {},
+ updateSavingsAccount = {},
+ withdrawSavingsAccount = {},
+ )
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationContent.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationContent.kt
similarity index 72%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationContent.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationContent.kt
index ee5b7a03c..bc79215a4 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationContent.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationContent.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_application
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountApplication
import android.content.Context
import android.widget.Toast
@@ -9,10 +18,6 @@ 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.material.icons.Icons
-import androidx.compose.material.icons.filled.ArrowDropDown
-import androidx.compose.material.icons.filled.ArrowDropUp
-import androidx.compose.material3.Button
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
@@ -35,24 +40,26 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.mifos.mobile.core.common.utils.getTodayFormatted
+import org.mifos.mobile.core.designsystem.components.MifosButton
+import org.mifos.mobile.core.designsystem.icons.MifosIcons
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
@Composable
-fun SavingsAccountApplicationContent(
+internal fun SavingsAccountApplicationContent(
+ submit: (Int, Int, showToast: (Int) -> Unit) -> Unit,
+ modifier: Modifier = Modifier,
existingProduct: String? = null,
savingsAccountTemplate: SavingsAccountTemplate? = null,
- submit: (Int, Int, showToast: (Int) -> Unit) -> Unit
) {
var selectProductId by rememberSaveable { mutableIntStateOf(-1) }
val context = LocalContext.current
- Column(modifier = Modifier.padding(16.dp)) {
-
+ Column(modifier = modifier.padding(16.dp)) {
OutlinedCard(
colors = CardDefaults.outlinedCardColors(
containerColor = MaterialTheme.colorScheme.background,
@@ -61,12 +68,12 @@ fun SavingsAccountApplicationContent(
Column(modifier = Modifier.padding(20.dp)) {
TitleBodyRow(
titleText = stringResource(R.string.client_name),
- bodyText = savingsAccountTemplate?.clientName ?: ""
+ bodyText = savingsAccountTemplate?.clientName ?: "",
)
Spacer(modifier = Modifier.height(16.dp))
TitleBodyRow(
titleText = stringResource(R.string.submission_date),
- bodyText = getTodayFormatted()
+ bodyText = getTodayFormatted(),
)
}
}
@@ -75,40 +82,41 @@ fun SavingsAccountApplicationContent(
SelectProductIdDropDown(
existingProduct = existingProduct,
+ selectProductId = { selectProductId = it },
savingsAccountTemplate = savingsAccountTemplate,
- selectProductId = { selectProductId = it }
)
Spacer(modifier = Modifier.height(20.dp))
- Button(
+ MifosButton(
+ textResId = R.string.submit,
modifier = Modifier.fillMaxWidth(),
onClick = {
submit(selectProductId, savingsAccountTemplate?.clientId ?: -1) {
showToast(context, it)
}
},
- content = { Text(text = stringResource(id = R.string.submit)) }
)
}
}
-private fun showToast(context: Context, messageResId: Int){
+private fun showToast(context: Context, messageResId: Int) {
Toast.makeText(context, context.getString(messageResId), Toast.LENGTH_LONG).show()
}
@Composable
-fun SelectProductIdDropDown(
+private fun SelectProductIdDropDown(
existingProduct: String?,
+ selectProductId: (Int) -> Unit,
+ modifier: Modifier = Modifier,
savingsAccountTemplate: SavingsAccountTemplate? = null,
- selectProductId: (Int) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
var selectedProduct by remember { mutableStateOf(existingProduct ?: "") }
val productOptions = savingsAccountTemplate?.productOptions.orEmpty()
Column(
- modifier = Modifier
+ modifier = modifier,
) {
OutlinedTextField(
value = selectedProduct,
@@ -122,22 +130,25 @@ fun SelectProductIdDropDown(
colors = TextFieldDefaults.colors(
disabledTextColor = MaterialTheme.colorScheme.onSurface,
disabledContainerColor = MaterialTheme.colorScheme.background,
- disabledLabelColor = MaterialTheme.colorScheme.onSurface
+ disabledLabelColor = MaterialTheme.colorScheme.onSurface,
),
trailingIcon = {
Icon(
- imageVector = if (expanded) Icons.Filled.ArrowDropUp
- else Icons.Filled.ArrowDropDown,
+ imageVector = if (expanded) {
+ MifosIcons.ArrowDropUp
+ } else {
+ MifosIcons.ArrowDropDown
+ },
contentDescription = "Dropdown",
)
- }
+ },
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier
.fillMaxWidth()
- .padding(horizontal = 4.dp)
+ .padding(horizontal = 4.dp),
) {
productOptions.forEach { product ->
DropdownMenuItem(
@@ -146,7 +157,7 @@ fun SelectProductIdDropDown(
selectedProduct = product.name ?: ""
expanded = false
},
- text = { Text(text = product.name ?: "") }
+ text = { Text(text = product.name ?: "") },
)
}
}
@@ -154,30 +165,40 @@ fun SelectProductIdDropDown(
}
@Composable
-fun TitleBodyRow(titleText: String, bodyText: String, modifier: Modifier = Modifier) {
- Row(verticalAlignment = Alignment.CenterVertically) {
+private fun TitleBodyRow(
+ titleText: String,
+ bodyText: String,
+ modifier: Modifier = Modifier,
+) {
+ Row(
+ modifier = modifier,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
Text(
text = titleText,
style = MaterialTheme.typography.labelMedium,
modifier = Modifier
.alpha(0.7f)
- .weight(2f)
+ .weight(2f),
)
Text(
text = bodyText,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.weight(3f),
- textAlign = TextAlign.Center
+ textAlign = TextAlign.Center,
)
}
}
-
-@Preview(showSystemUi = true)
+@DevicePreviews
@Composable
-fun SavingsAccountApplicationContentPreview() {
+private fun SavingsAccountApplicationContentPreview() {
MifosMobileTheme {
- SavingsAccountApplicationContent(null, null, {i, j, k -> })
+ SavingsAccountApplicationContent(
+ submit = { _, _, _ -> },
+ existingProduct = null,
+ savingsAccountTemplate = null,
+ )
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationScreen.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationScreen.kt
similarity index 71%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationScreen.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationScreen.kt
index 285f431fa..0a822b02a 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationScreen.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationScreen.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_application
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountApplication
import android.widget.Toast
import androidx.compose.foundation.layout.Box
@@ -12,7 +21,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.tooling.preview.Preview
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.mifos.mobile.core.designsystem.components.MifosScaffold
@@ -22,29 +30,32 @@ import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociatio
import org.mifos.mobile.core.model.enums.SavingsAccountState
import org.mifos.mobile.core.ui.component.MifosErrorComponent
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
-
@Composable
-fun SavingsAccountApplicationScreen(
- viewModel: SavingsAccountApplicationViewModel = hiltViewModel(),
+internal fun SavingsAccountApplicationScreen(
navigateBack: () -> Unit,
+ modifier: Modifier = Modifier,
+ viewModel: SavingsAccountApplicationViewModel = hiltViewModel(),
) {
val uiState by viewModel.savingsAccountApplicationUiState.collectAsStateWithLifecycle()
SavingsAccountApplicationScreen(
uiState = uiState,
navigateBack = navigateBack,
- submit = viewModel::onSubmit
+ submit = viewModel::onSubmit,
+ modifier = modifier,
)
}
@Composable
-fun SavingsAccountApplicationScreen(
+private fun SavingsAccountApplicationScreen(
uiState: SavingsAccountApplicationUiState,
- savingsWithAssociations: SavingsWithAssociations? = null,
navigateBack: () -> Unit,
submit: (Int, Int, showToast: (Int) -> Unit) -> Unit,
+ modifier: Modifier = Modifier,
+ savingsWithAssociations: SavingsWithAssociations? = null,
) {
var topBarTitleText by rememberSaveable { mutableStateOf("") }
val context = LocalContext.current
@@ -53,15 +64,14 @@ fun SavingsAccountApplicationScreen(
topBar = {
MifosTopBar(
navigateBack = navigateBack,
- title = { Text(text = topBarTitleText) }
+ title = { Text(text = topBarTitleText) },
)
},
+ modifier = modifier,
content = {
Box(modifier = Modifier.padding(it)) {
when (uiState) {
- is SavingsAccountApplicationUiState.Error -> {
- MifosErrorComponent()
- }
+ is SavingsAccountApplicationUiState.Error -> MifosErrorComponent()
is SavingsAccountApplicationUiState.Loading -> {
MifosProgressIndicatorOverlay()
@@ -75,9 +85,9 @@ fun SavingsAccountApplicationScreen(
topBarTitleText = stringResource(id = titleResourceId)
SavingsAccountApplicationContent(
+ submit = submit,
existingProduct = existingProduct,
savingsAccountTemplate = uiState.template,
- submit = submit
)
}
@@ -86,21 +96,28 @@ fun SavingsAccountApplicationScreen(
SavingsAccountState.CREATE -> R.string.new_saving_account_created_successfully
else -> R.string.saving_account_updated_successfully
}
- Toast.makeText(context, stringResource(id = messageResourceId), Toast.LENGTH_SHORT).show()
+ Toast.makeText(
+ context,
+ stringResource(id = messageResourceId),
+ Toast.LENGTH_SHORT,
+ ).show()
navigateBack.invoke()
}
}
-
}
- }
+ },
)
}
-@Preview(showSystemUi = true)
+@DevicePreviews
@Composable
-fun SavingsAccountApplicationScreenPreview() {
+private fun SavingsAccountApplicationScreenPreview() {
MifosMobileTheme {
- SavingsAccountApplicationScreen(SavingsAccountApplicationUiState.Success(requestType = SavingsAccountState.UPDATE), null, {}, { i, j, k -> })
+ SavingsAccountApplicationScreen(
+ SavingsAccountApplicationUiState.Success(requestType = SavingsAccountState.UPDATE),
+ navigateBack = {},
+ submit = { _, _, _ -> },
+ savingsWithAssociations = null,
+ )
}
}
-
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationViewModel.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationViewModel.kt
similarity index 72%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationViewModel.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationViewModel.kt
index ecf8e2cd0..95828b737 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_application/SavingsAccountApplicationViewModel.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountApplication/SavingsAccountApplicationViewModel.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_application
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountApplication
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@@ -7,6 +16,7 @@ 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.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.stateIn
@@ -22,44 +32,46 @@ import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociatio
import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate
import org.mifos.mobile.core.model.enums.SavingsAccountState
import org.mifos.mobile.feature.savings.R
+import org.mifos.mobile.feature.savings.savingsAccountApplication.SavingsAccountApplicationUiState.Loading
import javax.inject.Inject
@HiltViewModel
-class SavingsAccountApplicationViewModel @Inject constructor(
+internal class SavingsAccountApplicationViewModel @Inject constructor(
private val savingsAccountRepositoryImp: SavingsAccountRepository,
private val preferencesHelper: PreferencesHelper,
- savedStateHandle: SavedStateHandle
+ savedStateHandle: SavedStateHandle,
) : ViewModel() {
- val savingsAccountApplicationUiState: StateFlow get() = _savingsAccountApplicationUiState
- private val _savingsAccountApplicationUiState =
- MutableStateFlow(SavingsAccountApplicationUiState.Loading)
-
-
private val clientId get() = preferencesHelper.clientId
- val savingsId = savedStateHandle.getStateFlow(key = Constants.SAVINGS_ID, initialValue = -1L)
- val savingsAccountState = savedStateHandle.getStateFlow(
+ private val savingsId =
+ savedStateHandle.getStateFlow(key = Constants.SAVINGS_ID, initialValue = -1L)
+ private val savingsAccountState = savedStateHandle.getStateFlow(
key = Constants.SAVINGS_ACCOUNT_STATE,
- initialValue = SavingsAccountState.CREATE
+ initialValue = SavingsAccountState.CREATE,
)
- var savingsWithAssociations: StateFlow = savingsId
+ private val _savingsAccountApplicationUiState =
+ MutableStateFlow(Loading)
+ val savingsAccountApplicationUiState = _savingsAccountApplicationUiState.asStateFlow()
+
+ private val savingsWithAssociations: StateFlow = savingsId
.flatMapLatest {
savingsAccountRepositoryImp.getSavingsWithAssociations(
- savingsId.value, Constants.TRANSACTIONS,
+ savingsId.value,
+ Constants.TRANSACTIONS,
)
}
.also { loadSavingsAccountApplicationTemplate() }
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
- initialValue = null
+ initialValue = null,
)
- fun loadSavingsAccountApplicationTemplate() {
+ private fun loadSavingsAccountApplicationTemplate() {
viewModelScope.launch {
- _savingsAccountApplicationUiState.value = SavingsAccountApplicationUiState.Loading
+ _savingsAccountApplicationUiState.value = Loading
savingsAccountRepositoryImp.getSavingAccountApplicationTemplate(clientId).catch { e ->
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error(e.message)
@@ -67,15 +79,15 @@ class SavingsAccountApplicationViewModel @Inject constructor(
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.ShowUserInterface(
it,
- savingsAccountState.value
+ savingsAccountState.value,
)
}
}
}
- fun submitSavingsAccountApplication(payload: SavingsAccountApplicationPayload?) {
+ private fun submitSavingsAccountApplication(payload: SavingsAccountApplicationPayload?) {
viewModelScope.launch {
- _savingsAccountApplicationUiState.value = SavingsAccountApplicationUiState.Loading
+ _savingsAccountApplicationUiState.value = Loading
savingsAccountRepositoryImp.submitSavingAccountApplication(payload).catch { e ->
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error(e.message)
@@ -86,9 +98,9 @@ class SavingsAccountApplicationViewModel @Inject constructor(
}
}
- fun updateSavingsAccount(accountId: Long?, payload: SavingsAccountUpdatePayload?) {
+ private fun updateSavingsAccount(accountId: Long?, payload: SavingsAccountUpdatePayload?) {
viewModelScope.launch {
- _savingsAccountApplicationUiState.value = SavingsAccountApplicationUiState.Loading
+ _savingsAccountApplicationUiState.value = Loading
savingsAccountRepositoryImp.updateSavingsAccount(accountId, payload).catch { e ->
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error(e.message)
@@ -133,14 +145,13 @@ class SavingsAccountApplicationViewModel @Inject constructor(
}
}
-sealed class SavingsAccountApplicationUiState {
+internal sealed class SavingsAccountApplicationUiState {
data object Loading : SavingsAccountApplicationUiState()
data class Error(val errorMessage: String?) : SavingsAccountApplicationUiState()
data class Success(val requestType: SavingsAccountState) : SavingsAccountApplicationUiState()
data class ShowUserInterface(
val template: SavingsAccountTemplate,
- val requestType: SavingsAccountState
+ val requestType: SavingsAccountState,
) :
SavingsAccountApplicationUiState()
}
-
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountTransactionContent.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountTransactionContent.kt
similarity index 76%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountTransactionContent.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountTransactionContent.kt
index 6d22c94e3..27f761e83 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountTransactionContent.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountTransactionContent.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_transaction
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountTransaction
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
@@ -32,12 +41,13 @@ import org.mifos.mobile.core.model.entity.accounts.savings.Transactions
import org.mifos.mobile.feature.savings.R
@Composable
-fun SavingsAccountTransactionContent(
+internal fun SavingsAccountTransactionContent(
transactionList: List,
+ modifier: Modifier = Modifier,
) {
Column(
- modifier = Modifier.fillMaxSize(),
- verticalArrangement = Arrangement.SpaceBetween
+ modifier = modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.SpaceBetween,
) {
LazyColumn {
items(items = transactionList) {
@@ -45,7 +55,7 @@ fun SavingsAccountTransactionContent(
HorizontalDivider(
thickness = 1.dp,
color = Color.Gray,
- modifier = Modifier.padding(vertical = 4.dp)
+ modifier = Modifier.padding(vertical = 4.dp),
)
}
}
@@ -54,42 +64,44 @@ fun SavingsAccountTransactionContent(
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 10.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp),
- verticalAlignment = Alignment.Bottom
+ verticalAlignment = Alignment.Bottom,
) {
Text(
text = stringResource(id = R.string.need_help),
- color = MaterialTheme.colorScheme.onSurface
+ color = MaterialTheme.colorScheme.onSurface,
)
Spacer(modifier = Modifier.width(2.dp))
Text(
text = stringResource(id = R.string.help_line_number),
- color = MaterialTheme.colorScheme.primary
+ color = MaterialTheme.colorScheme.primary,
)
}
}
}
-
@Composable
-fun SavingsAccountTransactionListItem(transaction: Transactions) {
+private fun SavingsAccountTransactionListItem(
+ transaction: Transactions,
+ modifier: Modifier = Modifier,
+) {
val context = LocalContext.current
Row(
- modifier = Modifier
+ modifier = modifier
.fillMaxWidth()
- .padding(vertical = 6.dp)
+ .padding(vertical = 6.dp),
) {
Image(
painter = painterResource(
- id = getTransactionTriangleResId(transaction.transactionType)
+ id = getTransactionTriangleResId(transaction.transactionType),
),
contentDescription = stringResource(id = R.string.savings_account_transaction),
modifier = Modifier
.size(56.dp)
- .padding(4.dp)
+ .padding(4.dp),
)
Column(
- modifier = Modifier.padding(4.dp)
+ modifier = Modifier.padding(4.dp),
) {
Row(
modifier = Modifier.fillMaxWidth(),
@@ -98,47 +110,47 @@ fun SavingsAccountTransactionListItem(transaction: Transactions) {
Text(
text = DateHelper.getDateAsString(transaction.date),
style = MaterialTheme.typography.labelLarge,
- color = MaterialTheme.colorScheme.onSurface
+ color = MaterialTheme.colorScheme.onSurface,
)
Text(
text = stringResource(
id = R.string.string_and_string,
transaction.currency?.displaySymbol ?: transaction.currency?.code ?: "",
- CurrencyUtil.formatCurrency(context, transaction.amount,)
+ CurrencyUtil.formatCurrency(context, transaction.amount),
),
style = MaterialTheme.typography.labelLarge,
- color = MaterialTheme.colorScheme.onSurface
+ color = MaterialTheme.colorScheme.onSurface,
)
}
Row(
modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.SpaceBetween
+ horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = transaction.transactionType?.value ?: "",
style = MaterialTheme.typography.labelMedium,
modifier = Modifier.alpha(0.7f),
- color = MaterialTheme.colorScheme.onSurface
+ color = MaterialTheme.colorScheme.onSurface,
)
Text(
text = stringResource(
id = R.string.string_and_string,
transaction.currency?.displaySymbol ?: transaction.currency?.code ?: "",
- CurrencyUtil.formatCurrency(context, transaction.runningBalance)
+ CurrencyUtil.formatCurrency(context, transaction.runningBalance),
),
style = MaterialTheme.typography.labelMedium,
modifier = Modifier.alpha(0.7f),
- color = MaterialTheme.colorScheme.onSurface
+ color = MaterialTheme.colorScheme.onSurface,
)
}
Row(
- modifier = Modifier.fillMaxWidth()
+ modifier = Modifier.fillMaxWidth(),
) {
Text(
text = transaction.paymentDetailData?.paymentType?.name.toString(),
style = MaterialTheme.typography.labelMedium,
modifier = Modifier.alpha(0.7f),
- color = MaterialTheme.colorScheme.onSurface
+ color = MaterialTheme.colorScheme.onSurface,
)
}
}
@@ -147,8 +159,8 @@ fun SavingsAccountTransactionListItem(transaction: Transactions) {
@Preview
@Composable
-fun SavingsAccountTransactionContentPreview() {
+private fun SavingsAccountTransactionContentPreview() {
MifosMobileTheme {
SavingsAccountTransactionContent(transactionList = listOf())
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionFilterDialog.kt
similarity index 78%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionFilterDialog.kt
index 1a00e2328..2b7fc2d88 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionFilterDialog.kt
@@ -1,5 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_transaction
-
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountTransaction
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
@@ -10,13 +18,13 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.Card
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@@ -26,26 +34,27 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.window.Dialog
import org.mifos.mobile.core.common.utils.DateHelper
import org.mifos.mobile.core.common.utils.DateHelper.getDateAsStringFromLong
import org.mifos.mobile.core.designsystem.components.MifosIconTextButton
import org.mifos.mobile.core.designsystem.components.MifosRadioButton
+import org.mifos.mobile.core.designsystem.components.MifosTextButton
import org.mifos.mobile.core.designsystem.icons.MifosIcons
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.ui.component.MifosCheckBox
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
import java.time.Instant
+@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun SavingsTransactionFilterDialog(
+internal fun SavingsTransactionFilterDialog(
onDismiss: () -> Unit,
savingsTransactionFilterDataModel: SavingsTransactionFilterDataModel,
filter: (SavingsTransactionFilterDataModel) -> Unit,
+ modifier: Modifier = Modifier,
) {
-
var radioFilter by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.radioFilter) }
val checkBoxFilters by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.checkBoxFilters) }
var startDate by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.startDate) }
@@ -58,7 +67,7 @@ fun SavingsTransactionFilterDialog(
LaunchedEffect(key1 = checkBoxFilters) {
checkBoxFilters.forEach { filter ->
- when(filter) {
+ when (filter) {
SavingsTransactionCheckBoxFilter.DEPOSIT -> isDepositChecked = true
SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> isDividendPayoutChecked = true
SavingsTransactionCheckBoxFilter.WITHDRAWAL -> isWithdrawalChecked = true
@@ -67,12 +76,13 @@ fun SavingsTransactionFilterDialog(
}
}
- Dialog(
- onDismissRequest = { onDismiss.invoke() },
+ BasicAlertDialog(
+ onDismissRequest = onDismiss,
+ modifier = modifier,
) {
Card(shape = RoundedCornerShape(20.dp)) {
Column(
- modifier = Modifier.padding(vertical = 20.dp, horizontal = 10.dp)
+ modifier = Modifier.padding(vertical = 20.dp, horizontal = 10.dp),
) {
Text(text = stringResource(id = R.string.select_you_want))
@@ -82,29 +92,41 @@ fun SavingsTransactionFilterDialog(
selectedStartDate = startDate,
selectedEndDate = endDate,
radioFilter = radioFilter,
- selectRadioFilter = { radioFilter = it },
- setStartDate = { startDate = it },
isDepositChecked = isDepositChecked,
+ isDividendPayoutChecked = isDividendPayoutChecked,
isWithdrawalChecked = isWithdrawalChecked,
isInterestPostingChecked = isInterestPostingChecked,
- isDividendPayoutChecked = isDividendPayoutChecked,
- setEndDate = { endDate = it },
+ selectRadioFilter = { radioFilter = it },
toggleCheckBox = { filter, isEnabled ->
- when(filter) {
+ when (filter) {
SavingsTransactionCheckBoxFilter.DEPOSIT -> isDepositChecked = isEnabled
- SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> isDividendPayoutChecked = isEnabled
- SavingsTransactionCheckBoxFilter.WITHDRAWAL -> isWithdrawalChecked = isEnabled
- SavingsTransactionCheckBoxFilter.INTEREST_POSTING -> isInterestPostingChecked = isEnabled
+ SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT ->
+ isDividendPayoutChecked =
+ isEnabled
+
+ SavingsTransactionCheckBoxFilter.WITHDRAWAL ->
+ isWithdrawalChecked =
+ isEnabled
+
+ SavingsTransactionCheckBoxFilter.INTEREST_POSTING ->
+ isInterestPostingChecked =
+ isEnabled
}
- if(isEnabled) checkBoxFilters.add(filter)
- else checkBoxFilters.remove(filter)
- }
+ if (isEnabled) {
+ checkBoxFilters.add(filter)
+ } else {
+ checkBoxFilters.remove(filter)
+ }
+ },
+ setStartDate = { startDate = it },
+ setEndDate = { endDate = it },
)
Spacer(modifier = Modifier.height(20.dp))
Row {
- TextButton(
+ MifosTextButton(
+ text = stringResource(R.string.clear_filters),
onClick = {
radioFilter = null
isDepositChecked = false
@@ -112,20 +134,18 @@ fun SavingsTransactionFilterDialog(
isInterestPostingChecked = false
isDividendPayoutChecked = false
checkBoxFilters.clear()
- }
- ) {
- Text(text = stringResource(id = R.string.clear_filters))
- }
+ },
+ )
Spacer(modifier = Modifier.weight(1f))
- TextButton(
- onClick = { onDismiss() }
- ) {
- Text(text = stringResource(id = R.string.cancel))
- }
+ MifosTextButton(
+ onClick = onDismiss,
+ text = stringResource(id = R.string.cancel),
+ )
- TextButton(
+ MifosTextButton(
+ text = stringResource(id = R.string.filter),
onClick = {
onDismiss()
filter(
@@ -133,13 +153,11 @@ fun SavingsTransactionFilterDialog(
startDate = startDate,
endDate = endDate,
radioFilter = radioFilter,
- checkBoxFilters = checkBoxFilters
- )
+ checkBoxFilters = checkBoxFilters,
+ ),
)
- }
- ) {
- Text(text = stringResource(id = R.string.filter))
- }
+ },
+ )
}
}
}
@@ -148,23 +166,26 @@ fun SavingsTransactionFilterDialog(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun SavingsTransactionFilterDialogContent(
+private fun SavingsTransactionFilterDialogContent(
selectedStartDate: Long,
selectedEndDate: Long,
radioFilter: SavingsTransactionRadioFilter?,
- selectRadioFilter: (SavingsTransactionRadioFilter) -> Unit,
isDepositChecked: Boolean,
isDividendPayoutChecked: Boolean,
isWithdrawalChecked: Boolean,
isInterestPostingChecked: Boolean,
+ selectRadioFilter: (SavingsTransactionRadioFilter) -> Unit,
toggleCheckBox: (SavingsTransactionCheckBoxFilter, Boolean) -> Unit,
setStartDate: (Long) -> Unit,
- setEndDate: (Long) -> Unit
+ setEndDate: (Long) -> Unit,
+ modifier: Modifier = Modifier,
) {
val scrollState = rememberScrollState()
+
var showStartDatePickerDialog by rememberSaveable { mutableStateOf(false) }
var showEndDatePickerDialog by rememberSaveable { mutableStateOf(false) }
- val startDatePickerState = rememberDatePickerState(initialSelectedDateMillis = selectedStartDate)
+ val startDatePickerState =
+ rememberDatePickerState(initialSelectedDateMillis = selectedStartDate)
val endDatePickerState = rememberDatePickerState(initialSelectedDateMillis = selectedEndDate)
var isDatesEnabled by rememberSaveable { mutableStateOf(false) }
@@ -192,13 +213,14 @@ fun SavingsTransactionFilterDialogContent(
}
Column(
- modifier = Modifier.scrollable(state = scrollState, orientation = Orientation.Vertical)
+ modifier = modifier
+ .scrollable(state = scrollState, orientation = Orientation.Vertical),
) {
SavingsTransactionRadioFilter.entries.forEach { filter ->
MifosRadioButton(
selected = radioFilter == filter,
onClick = { selectRadioFilter(filter) },
- textResId = filter.textResId
+ textResId = filter.textResId,
)
if (filter == SavingsTransactionRadioFilter.DATE) {
@@ -207,13 +229,13 @@ fun SavingsTransactionFilterDialogContent(
text = getDateAsStringFromLong(selectedStartDate),
imageVector = MifosIcons.Edit,
enabled = radioFilter == SavingsTransactionRadioFilter.DATE,
- onClick = { showStartDatePickerDialog = true }
+ onClick = { showStartDatePickerDialog = true },
)
MifosIconTextButton(
text = getDateAsStringFromLong(selectedEndDate),
imageVector = MifosIcons.Edit,
enabled = radioFilter == SavingsTransactionRadioFilter.DATE,
- onClick = { showEndDatePickerDialog = true }
+ onClick = { showEndDatePickerDialog = true },
)
}
}
@@ -221,7 +243,7 @@ fun SavingsTransactionFilterDialogContent(
SavingsTransactionCheckBoxFilter.entries.forEach { filter ->
MifosCheckBox(
- checked = when(filter) {
+ checked = when (filter) {
SavingsTransactionCheckBoxFilter.DEPOSIT -> isDepositChecked
SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> isDividendPayoutChecked
SavingsTransactionCheckBoxFilter.WITHDRAWAL -> isWithdrawalChecked
@@ -235,7 +257,7 @@ fun SavingsTransactionFilterDialogContent(
checkedBorderColor = filter.checkBoxColor,
uncheckedBorderColor = filter.checkBoxColor,
checkedBoxColor = filter.checkBoxColor,
- )
+ ),
)
}
}
@@ -244,8 +266,8 @@ fun SavingsTransactionFilterDialogContent(
DatePickerDialog(
onDismissRequest = { showStartDatePickerDialog = false },
confirmButton = {
- startDatePickerState.selectedDateMillis?.let{ setStartDate(it) }
- }
+ startDatePickerState.selectedDateMillis?.let { setStartDate(it) }
+ },
) { DatePicker(state = startDatePickerState) }
}
@@ -254,25 +276,24 @@ fun SavingsTransactionFilterDialogContent(
onDismissRequest = { showEndDatePickerDialog = false },
confirmButton = {
endDatePickerState.selectedDateMillis?.let { setEndDate(it) }
- }
+ },
) { DatePicker(state = endDatePickerState) }
}
}
-
-@Preview
+@DevicePreviews
@Composable
-fun SavingsTransactionFilterDialogPreview() {
+private fun SavingsTransactionFilterDialogPreview() {
MifosMobileTheme {
SavingsTransactionFilterDialog(
savingsTransactionFilterDataModel = SavingsTransactionFilterDataModel(
radioFilter = null,
checkBoxFilters = mutableListOf(),
startDate = Instant.now().toEpochMilli(),
- endDate = Instant.now().toEpochMilli()
+ endDate = Instant.now().toEpochMilli(),
),
filter = {},
onDismiss = {},
)
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionScreen.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionScreen.kt
similarity index 80%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionScreen.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionScreen.kt
index e495cff5f..3ee8da3e0 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionScreen.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionScreen.kt
@@ -1,5 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_transaction
-
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountTransaction
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
@@ -8,7 +16,6 @@ import androidx.compose.material3.IconButton
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.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
@@ -17,7 +24,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.hilt.navigation.compose.hiltViewModel
@@ -31,35 +37,34 @@ import org.mifos.mobile.core.model.entity.accounts.savings.Transactions
import org.mifos.mobile.core.ui.component.EmptyDataView
import org.mifos.mobile.core.ui.component.MifosErrorComponent
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
import java.time.Instant
@Composable
-fun SavingsAccountTransactionScreen(
- viewModel: SavingAccountsTransactionViewModel = hiltViewModel(),
+internal fun SavingsAccountTransactionScreen(
navigateBack: () -> Unit,
+ modifier: Modifier = Modifier,
+ viewModel: SavingAccountsTransactionViewModel = hiltViewModel(),
) {
- val uiState by viewModel.savingAccountsTransactionUiState.collectAsStateWithLifecycle()
- val savingsId by viewModel.savingsId.collectAsStateWithLifecycle()
-
- LaunchedEffect(key1 = savingsId) {
- viewModel.loadSavingsWithAssociations(accountId = savingsId)
- }
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
SavingsAccountTransactionScreen(
uiState = uiState,
navigateBack = navigateBack,
- retryConnection = { viewModel.loadSavingsWithAssociations(savingsId) },
- filterList = { viewModel.filterList(filter = it) }
+ retryConnection = viewModel::loadSavingsWithAssociations,
+ filterList = viewModel::filterList,
+ modifier = modifier,
)
}
@Composable
-fun SavingsAccountTransactionScreen(
+internal fun SavingsAccountTransactionScreen(
uiState: SavingsAccountTransactionUiState,
navigateBack: () -> Unit,
retryConnection: () -> Unit,
filterList: (SavingsTransactionFilterDataModel) -> Unit,
+ modifier: Modifier = Modifier,
) {
val context = LocalContext.current
var transactionList by rememberSaveable { mutableStateOf(listOf()) }
@@ -70,12 +75,13 @@ fun SavingsAccountTransactionScreen(
startDate = Instant.now().toEpochMilli(),
endDate = Instant.now().toEpochMilli(),
radioFilter = null,
- checkBoxFilters = mutableListOf()
- )
+ checkBoxFilters = mutableListOf(),
+ ),
)
}
MifosScaffold(
+ modifier = modifier,
topBar = {
MifosTopBar(
navigateBack = navigateBack,
@@ -83,7 +89,7 @@ fun SavingsAccountTransactionScreen(
Text(
text = stringResource(id = R.string.savings_account_transaction),
overflow = TextOverflow.Ellipsis,
- maxLines = 1
+ maxLines = 1,
)
},
actions = {
@@ -91,10 +97,10 @@ fun SavingsAccountTransactionScreen(
Icon(
imageVector = MifosIcons.FilterList,
contentDescription = null,
- tint = MaterialTheme.colorScheme.onSurface
+ tint = MaterialTheme.colorScheme.onSurface,
)
}
- }
+ },
)
},
content = { paddingValues ->
@@ -109,7 +115,7 @@ fun SavingsAccountTransactionScreen(
isNetworkConnected = Network.isConnected(context),
isEmptyData = false,
isRetryEnabled = true,
- onRetry = retryConnection
+ onRetry = retryConnection,
)
}
@@ -117,7 +123,7 @@ fun SavingsAccountTransactionScreen(
if (uiState.savingAccountsTransactionList.isNullOrEmpty()) {
EmptyDataView(
icon = R.drawable.ic_compare_arrows_black_24dp,
- error = R.string.no_transaction_found
+ error = R.string.no_transaction_found,
)
} else {
transactionList = uiState.savingAccountsTransactionList
@@ -126,7 +132,7 @@ fun SavingsAccountTransactionScreen(
}
}
}
- }
+ },
)
if (isDialogOpen) {
@@ -141,7 +147,7 @@ fun SavingsAccountTransactionScreen(
}
}
-class SavingsAccountTransactionUiStatesParameterProvider :
+internal class SavingsAccountTransactionUiStatesParameterProvider :
PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
@@ -151,17 +157,18 @@ class SavingsAccountTransactionUiStatesParameterProvider :
)
}
-@Preview(showSystemUi = true)
+@DevicePreviews
@Composable
-fun SavingsAccountTransactionScreenPreview(
- @PreviewParameter(SavingsAccountTransactionUiStatesParameterProvider::class) savingsAccountUiState: SavingsAccountTransactionUiState
+private fun SavingsAccountTransactionScreenPreview(
+ @PreviewParameter(SavingsAccountTransactionUiStatesParameterProvider::class)
+ savingsAccountUiState: SavingsAccountTransactionUiState,
) {
MifosMobileTheme {
SavingsAccountTransactionScreen(
uiState = savingsAccountUiState,
navigateBack = { },
retryConnection = { },
- filterList = { }
+ filterList = { },
)
}
-}
\ No newline at end of file
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionViewModel.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionViewModel.kt
similarity index 70%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionViewModel.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionViewModel.kt
index 6f7028b73..75b282cc6 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_transaction/SavingAccountsTransactionViewModel.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountTransaction/SavingAccountsTransactionViewModel.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_transaction
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountTransaction
import android.os.Parcelable
import androidx.compose.ui.graphics.Color
@@ -8,6 +17,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
@@ -20,40 +30,42 @@ import org.mifos.mobile.core.designsystem.theme.RedLight
import org.mifos.mobile.core.model.entity.accounts.savings.TransactionType
import org.mifos.mobile.core.model.entity.accounts.savings.Transactions
import org.mifos.mobile.feature.savings.R
+import org.mifos.mobile.feature.savings.savingsAccountTransaction.SavingsAccountTransactionUiState.Loading
import javax.inject.Inject
@HiltViewModel
-class SavingAccountsTransactionViewModel @Inject constructor(
+internal class SavingAccountsTransactionViewModel @Inject constructor(
private val savingsAccountRepositoryImp: SavingsAccountRepository,
- savedStateHandle: SavedStateHandle
-) :
- ViewModel() {
+ savedStateHandle: SavedStateHandle,
+) : ViewModel() {
- private val _savingAccountsTransactionUiState = MutableStateFlow(
- SavingsAccountTransactionUiState.Loading
- )
- val savingAccountsTransactionUiState: StateFlow get() = _savingAccountsTransactionUiState
+ private val mUiState = MutableStateFlow(Loading)
+ val uiState = mUiState.asStateFlow()
private var _transactionsList: List = mutableListOf()
private val transactionsList: List get() = _transactionsList
- val savingsId: StateFlow = savedStateHandle.getStateFlow(
+ private val savingsId: StateFlow = savedStateHandle.getStateFlow(
key = SAVINGS_ID,
- initialValue = -1L
+ initialValue = -1L,
)
- fun loadSavingsWithAssociations(accountId: Long) {
+ init {
+ loadSavingsWithAssociations()
+ }
+
+ fun loadSavingsWithAssociations(accountId: Long = savingsId.value) {
viewModelScope.launch {
- _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Loading
+ mUiState.value = Loading
savingsAccountRepositoryImp.getSavingsWithAssociations(
accountId,
org.mifos.mobile.core.common.Constants.TRANSACTIONS,
).catch {
- _savingAccountsTransactionUiState.value =
+ mUiState.value =
SavingsAccountTransactionUiState.Error(it.message)
}.collect {
_transactionsList = it.transactions
- _savingAccountsTransactionUiState.value =
+ mUiState.value =
SavingsAccountTransactionUiState.Success(it.transactions)
}
}
@@ -65,55 +77,66 @@ class SavingAccountsTransactionViewModel @Inject constructor(
filterByDateAndType(
startDate = filter.startDate,
endDate = filter.endDate,
- checkBoxFilters = filter.checkBoxFilters
+ checkBoxFilters = filter.checkBoxFilters,
)
}
+
filter.radioFilter != null -> {
filterByDate(
startDate = filter.startDate,
- endDate = filter.endDate
+ endDate = filter.endDate,
)
}
+
filter.checkBoxFilters.isNotEmpty() -> {
filterByType(
- checkBoxFilters = filter.checkBoxFilters
+ checkBoxFilters = filter.checkBoxFilters,
)
}
+
else -> {
- _savingAccountsTransactionUiState.value =
+ mUiState.value =
SavingsAccountTransactionUiState.Success(transactionsList)
}
}
}
-
private fun filterByDateAndType(
startDate: Long,
endDate: Long,
- checkBoxFilters: MutableList
+ checkBoxFilters: MutableList,
) {
- val typeFilteredList = filterSavingsAccountTransactionsByType(checkBoxFilters = checkBoxFilters)
- val dateAndTypeFilteredList = filterTransactionListByDate(transactions = typeFilteredList, startDate = startDate, endDate = endDate)
- _savingAccountsTransactionUiState.value =
+ val typeFilteredList =
+ filterSavingsAccountTransactionsByType(checkBoxFilters = checkBoxFilters)
+ val dateAndTypeFilteredList = filterTransactionListByDate(
+ transactions = typeFilteredList,
+ startDate = startDate,
+ endDate = endDate,
+ )
+ mUiState.value =
SavingsAccountTransactionUiState.Success(dateAndTypeFilteredList)
}
private fun filterByDate(startDate: Long, endDate: Long) {
- val list = filterTransactionListByDate(transactions = transactionsList, startDate = startDate, endDate = endDate)
- _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Success(list)
+ val list = filterTransactionListByDate(
+ transactions = transactionsList,
+ startDate = startDate,
+ endDate = endDate,
+ )
+ mUiState.value = SavingsAccountTransactionUiState.Success(list)
}
private fun filterByType(
- checkBoxFilters: MutableList
+ checkBoxFilters: MutableList,
) {
val list = filterSavingsAccountTransactionsByType(checkBoxFilters = checkBoxFilters)
- _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Success(list)
+ mUiState.value = SavingsAccountTransactionUiState.Success(list)
}
private fun filterTransactionListByDate(
transactions: List,
startDate: Long,
- endDate: Long
+ endDate: Long,
): List {
return transactions.filter {
(DateHelper.getDateAsLongFromList(it.date) in startDate..endDate)
@@ -121,7 +144,7 @@ class SavingAccountsTransactionViewModel @Inject constructor(
}
private fun filterSavingsAccountTransactionsByType(
- checkBoxFilters: MutableList
+ checkBoxFilters: MutableList,
): List {
var filteredSavingsTransactions: List = ArrayList()
checkBoxFilters.forEach { filter ->
@@ -129,12 +152,15 @@ class SavingAccountsTransactionViewModel @Inject constructor(
SavingsTransactionCheckBoxFilter.DEPOSIT -> {
transactionsList.filter { it.transactionType?.deposit == true }
}
+
SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> {
transactionsList.filter { it.transactionType?.dividendPayout == true }
}
+
SavingsTransactionCheckBoxFilter.WITHDRAWAL -> {
transactionsList.filter { it.transactionType?.withdrawal == true }
}
+
SavingsTransactionCheckBoxFilter.INTEREST_POSTING -> {
transactionsList.filter { it.transactionType?.interestPosting == true }
}
@@ -145,13 +171,14 @@ class SavingAccountsTransactionViewModel @Inject constructor(
}
}
-sealed class SavingsAccountTransactionUiState {
+internal sealed class SavingsAccountTransactionUiState {
data object Loading : SavingsAccountTransactionUiState()
data class Error(val errorMessage: String?) : SavingsAccountTransactionUiState()
- data class Success(val savingAccountsTransactionList: List?) : SavingsAccountTransactionUiState()
+ data class Success(val savingAccountsTransactionList: List?) :
+ SavingsAccountTransactionUiState()
}
-fun getTransactionTriangleResId(transactionType: TransactionType?): Int {
+internal fun getTransactionTriangleResId(transactionType: TransactionType?): Int {
return transactionType?.run {
when {
deposit == true -> R.drawable.triangular_green_view
@@ -170,38 +197,38 @@ fun getTransactionTriangleResId(transactionType: TransactionType?): Int {
}
@Parcelize
-data class SavingsTransactionFilterDataModel(
+internal data class SavingsTransactionFilterDataModel(
val startDate: Long,
val endDate: Long,
val radioFilter: SavingsTransactionRadioFilter?,
- val checkBoxFilters: MutableList
-): Parcelable
+ val checkBoxFilters: MutableList,
+) : Parcelable
-enum class SavingsTransactionRadioFilter(val textResId: Int) {
+internal enum class SavingsTransactionRadioFilter(val textResId: Int) {
DATE(textResId = R.string.date),
FOUR_WEEKS(textResId = R.string.four_weeks),
THREE_MONTHS(textResId = R.string.three_months),
- SIX_MONTHS(textResId = R.string.six_months)
+ SIX_MONTHS(textResId = R.string.six_months),
}
-enum class SavingsTransactionCheckBoxFilter(
+internal enum class SavingsTransactionCheckBoxFilter(
val textResId: Int,
val checkBoxColor: Color,
) {
DEPOSIT(
textResId = R.string.deposit,
- checkBoxColor = DepositGreen
+ checkBoxColor = DepositGreen,
),
DIVIDEND_PAYOUT(
textResId = R.string.dividend_payout,
- checkBoxColor = RedLight
+ checkBoxColor = RedLight,
),
WITHDRAWAL(
textResId = R.string.withdrawal,
- checkBoxColor = RedLight
+ checkBoxColor = RedLight,
),
INTEREST_POSTING(
textResId = R.string.interest_posting,
- checkBoxColor = GreenSuccess
- )
-}
\ No newline at end of file
+ checkBoxColor = GreenSuccess,
+ ),
+}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_withdraw/SavingsAccountWithdrawScreen.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountWithdraw/SavingsAccountWithdrawScreen.kt
similarity index 71%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_withdraw/SavingsAccountWithdrawScreen.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountWithdraw/SavingsAccountWithdrawScreen.kt
index d530349fa..9df4624aa 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_withdraw/SavingsAccountWithdrawScreen.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountWithdraw/SavingsAccountWithdrawScreen.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_withdraw
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountWithdraw
import android.widget.Toast
import androidx.compose.foundation.background
@@ -9,7 +18,6 @@ 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.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -22,7 +30,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
-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
@@ -30,6 +37,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.mifos.mobile.core.common.Network
import org.mifos.mobile.core.common.utils.getTodayFormatted
+import org.mifos.mobile.core.designsystem.components.MifosButton
import org.mifos.mobile.core.designsystem.components.MifosOutlinedTextField
import org.mifos.mobile.core.designsystem.components.MifosTopBar
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
@@ -37,56 +45,65 @@ import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociatio
import org.mifos.mobile.core.ui.component.MifosProgressIndicator
import org.mifos.mobile.core.ui.component.MifosTitleDescSingleLineEqual
import org.mifos.mobile.core.ui.component.NoInternet
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
-
@Composable
-fun SavingsAccountWithdrawScreen(
- viewModel: SavingsAccountWithdrawViewModel = hiltViewModel(),
+internal fun SavingsAccountWithdrawScreen(
navigateBack: (withdrawSuccess: Boolean) -> Unit,
+ modifier: Modifier = Modifier,
+ viewModel: SavingsAccountWithdrawViewModel = hiltViewModel(),
) {
- val uiState by viewModel.savingsAccountWithdrawUiState.collectAsStateWithLifecycle()
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val savingsWithAssociations by viewModel.savingsWithAssociations.collectAsStateWithLifecycle()
SavingsAccountWithdrawScreen(
uiState = uiState,
savingsWithAssociations = savingsWithAssociations,
navigateBack = navigateBack,
- withdraw = { viewModel.submitWithdrawSavingsAccount(it) }
+ withdraw = viewModel::submitWithdrawSavingsAccount,
+ modifier = modifier,
)
}
@Composable
-fun SavingsAccountWithdrawScreen(
+private fun SavingsAccountWithdrawScreen(
uiState: SavingsAccountWithdrawUiState,
savingsWithAssociations: SavingsWithAssociations?,
navigateBack: (withdrawSuccess: Boolean) -> Unit,
withdraw: (String) -> Unit,
+ modifier: Modifier = Modifier,
) {
val context = LocalContext.current
- Column(modifier = Modifier.fillMaxSize()) {
+ Column(modifier = modifier.fillMaxSize()) {
MifosTopBar(
navigateBack = { navigateBack(false) },
- title = { Text(text = stringResource(id = R.string.withdraw_savings_account)) }
+ title = { Text(text = stringResource(id = R.string.withdraw_savings_account)) },
)
- Box(modifier= Modifier.weight(1f)) {
+ Box(modifier = Modifier.weight(1f)) {
SavingsAccountWithdrawContent(
savingsWithAssociations = savingsWithAssociations,
- withdraw = withdraw
+ withdraw = withdraw,
)
when (uiState) {
is SavingsAccountWithdrawUiState.Loading -> {
- MifosProgressIndicator(modifier = Modifier
- .fillMaxSize()
- .background(MaterialTheme.colorScheme.background.copy(alpha = 0.7f)))
+ MifosProgressIndicator(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.background.copy(alpha = 0.7f)),
+ )
}
is SavingsAccountWithdrawUiState.Success -> {
LaunchedEffect(true) {
- Toast.makeText(context, R.string.savings_account_withdraw_successful, Toast.LENGTH_SHORT).show()
+ Toast.makeText(
+ context,
+ R.string.savings_account_withdraw_successful,
+ Toast.LENGTH_SHORT,
+ ).show()
}
navigateBack(true)
}
@@ -98,12 +115,11 @@ fun SavingsAccountWithdrawScreen(
is SavingsAccountWithdrawUiState.WithdrawUiReady -> {}
}
}
-
}
}
@Composable
-fun ErrorComponent(
+private fun ErrorComponent(
errorToast: String?,
) {
val context = LocalContext.current
@@ -120,31 +136,32 @@ fun ErrorComponent(
}
@Composable
-fun SavingsAccountWithdrawContent(
+private fun SavingsAccountWithdrawContent(
savingsWithAssociations: SavingsWithAssociations?,
- withdraw: (String) -> Unit
+ withdraw: (String) -> Unit,
+ modifier: Modifier = Modifier,
) {
var remark by remember { mutableStateOf(TextFieldValue("")) }
var remarkFieldError by remember { mutableStateOf(false) }
Column(
- modifier = Modifier
+ modifier = modifier
.padding(16.dp)
- .fillMaxSize()
+ .fillMaxSize(),
) {
MifosTitleDescSingleLineEqual(
title = stringResource(id = R.string.client_name),
- description = savingsWithAssociations?.clientName ?: ""
+ description = savingsWithAssociations?.clientName ?: "",
)
Spacer(modifier = Modifier.height(8.dp))
MifosTitleDescSingleLineEqual(
title = stringResource(id = R.string.account_number),
- description = savingsWithAssociations?.accountNo ?: ""
+ description = savingsWithAssociations?.accountNo ?: "",
)
Spacer(modifier = Modifier.height(8.dp))
MifosTitleDescSingleLineEqual(
title = stringResource(id = R.string.withdrawal_date),
- description = getTodayFormatted()
+ description = getTodayFormatted(),
)
Spacer(modifier = Modifier.height(16.dp))
MifosOutlinedTextField(
@@ -154,15 +171,16 @@ fun SavingsAccountWithdrawContent(
modifier = Modifier.fillMaxWidth(),
supportingText = stringResource(
R.string.error_validation_blank,
- stringResource(R.string.remark)
+ stringResource(R.string.remark),
),
onValueChange = {
remark = it
remarkFieldError = false
- }
+ },
)
Spacer(modifier = Modifier.height(16.dp))
- Button(
+ MifosButton(
+ textResId = R.string.withdraw_savings_account,
onClick = {
if (remark.text.isEmpty()) {
remarkFieldError = true
@@ -170,34 +188,33 @@ fun SavingsAccountWithdrawContent(
withdraw.invoke(remark.text)
}
},
- modifier = Modifier.fillMaxWidth()
- ) {
- Text(text = stringResource(id = R.string.withdraw_savings_account))
- }
+ modifier = Modifier.fillMaxWidth(),
+ )
}
}
-class UiStatesParameterProvider : PreviewParameterProvider {
+internal class UiStatesParameterProvider : PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
SavingsAccountWithdrawUiState.WithdrawUiReady,
SavingsAccountWithdrawUiState.Error(message = ""),
SavingsAccountWithdrawUiState.Loading,
- SavingsAccountWithdrawUiState.Success
+ SavingsAccountWithdrawUiState.Success,
)
}
-@Preview(showSystemUi = true)
+@DevicePreviews
@Composable
-fun SavingsAccountWithdrawScreenPreview(
- @PreviewParameter(UiStatesParameterProvider::class) savingsAccountWithdrawUiState: SavingsAccountWithdrawUiState
+private fun SavingsAccountWithdrawScreenPreview(
+ @PreviewParameter(UiStatesParameterProvider::class)
+ savingsAccountWithdrawUiState: SavingsAccountWithdrawUiState,
) {
MifosMobileTheme {
SavingsAccountWithdrawScreen(
uiState = savingsAccountWithdrawUiState,
savingsWithAssociations = SavingsWithAssociations(
clientName = "Mifos Mobile",
- accountNo = "0001"
+ accountNo = "0001",
),
navigateBack = {},
withdraw = {},
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountWithdraw/SavingsAccountWithdrawViewModel.kt
similarity index 52%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountWithdraw/SavingsAccountWithdrawViewModel.kt
index f3244e009..f06c4dfd2 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsAccountWithdraw/SavingsAccountWithdrawViewModel.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_account_withdraw
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsAccountWithdraw
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@@ -7,6 +16,7 @@ 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.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.stateIn
@@ -15,33 +25,34 @@ import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.common.utils.getTodayFormatted
import org.mifos.mobile.core.data.repository.SavingsAccountRepository
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountWithdrawPayload
+import org.mifos.mobile.feature.savings.savingsAccountWithdraw.SavingsAccountWithdrawUiState.WithdrawUiReady
import javax.inject.Inject
@HiltViewModel
-class SavingsAccountWithdrawViewModel @Inject constructor(
+internal class SavingsAccountWithdrawViewModel @Inject constructor(
private val savingsAccountRepositoryImp: SavingsAccountRepository,
- savedStateHandle: SavedStateHandle
+ savedStateHandle: SavedStateHandle,
) : ViewModel() {
- val savingsAccountWithdrawUiState: StateFlow get() = _savingsAccountWithdrawUiState
- private val _savingsAccountWithdrawUiState = MutableStateFlow(
- SavingsAccountWithdrawUiState.WithdrawUiReady
- )
- val savingsId: StateFlow = savedStateHandle.getStateFlow(
+ private val mUiState = MutableStateFlow(WithdrawUiReady)
+ val uiState = mUiState.asStateFlow()
+
+ private val savingsId: StateFlow = savedStateHandle.getStateFlow(
key = Constants.SAVINGS_ID,
- initialValue = -1L
+ initialValue = -1L,
)
val savingsWithAssociations = savingsId
.flatMapLatest {
savingsAccountRepositoryImp.getSavingsWithAssociations(
- savingsId.value, Constants.TRANSACTIONS,
+ savingsId.value,
+ Constants.TRANSACTIONS,
)
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
- initialValue = null
+ initialValue = null,
)
fun submitWithdrawSavingsAccount(remark: String) {
@@ -50,22 +61,25 @@ class SavingsAccountWithdrawViewModel @Inject constructor(
payload.withdrawnOnDate = getTodayFormatted()
viewModelScope.launch {
- _savingsAccountWithdrawUiState.value = SavingsAccountWithdrawUiState.Loading
- savingsAccountRepositoryImp.submitWithdrawSavingsAccount(savingsWithAssociations.value?.accountNo, payload)
+ mUiState.value = SavingsAccountWithdrawUiState.Loading
+ savingsAccountRepositoryImp.submitWithdrawSavingsAccount(
+ savingsWithAssociations.value?.accountNo,
+ payload,
+ )
.catch { e ->
- _savingsAccountWithdrawUiState.value =
+ mUiState.value =
SavingsAccountWithdrawUiState.Error(e.message)
}.collect {
- _savingsAccountWithdrawUiState.value =
+ mUiState.value =
SavingsAccountWithdrawUiState.Success
}
}
}
}
-sealed class SavingsAccountWithdrawUiState {
- data object WithdrawUiReady: SavingsAccountWithdrawUiState()
- data object Loading: SavingsAccountWithdrawUiState()
- data object Success: SavingsAccountWithdrawUiState()
- data class Error(val message: String?): SavingsAccountWithdrawUiState()
+internal sealed class SavingsAccountWithdrawUiState {
+ data object WithdrawUiReady : SavingsAccountWithdrawUiState()
+ data object Loading : SavingsAccountWithdrawUiState()
+ data object Success : SavingsAccountWithdrawUiState()
+ data class Error(val message: String?) : SavingsAccountWithdrawUiState()
}
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_make_transfer/SavingsMakeTransferContent.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsMakeTransfer/SavingsMakeTransferContent.kt
similarity index 75%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_make_transfer/SavingsMakeTransferContent.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsMakeTransfer/SavingsMakeTransferContent.kt
index 0a69fe631..ff6a7864f 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_make_transfer/SavingsMakeTransferContent.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsMakeTransfer/SavingsMakeTransferContent.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_make_transfer
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsMakeTransfer
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -9,9 +18,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
@@ -26,13 +33,13 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import org.mifos.mobile.core.designsystem.components.MifosButton
+import org.mifos.mobile.core.designsystem.components.MifosOutlinedButton
import org.mifos.mobile.core.designsystem.components.MifosOutlinedTextField
import org.mifos.mobile.core.designsystem.theme.DarkGray
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
@@ -43,13 +50,15 @@ import org.mifos.mobile.core.ui.component.MFStepProcess
import org.mifos.mobile.core.ui.component.MifosDropDownDoubleTextField
import org.mifos.mobile.core.ui.component.StepProcessState
import org.mifos.mobile.core.ui.component.getStepState
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
@Composable
-fun SavingsMakeTransferContent(
+internal fun SavingsMakeTransferContent(
uiData: SavingsMakeTransferUiData,
+ reviewTransfer: (ReviewTransferPayload) -> Unit,
+ modifier: Modifier = Modifier,
onCancelledClicked: () -> Unit = {},
- reviewTransfer: (ReviewTransferPayload) -> Unit
) {
val scrollState = rememberScrollState()
@@ -82,14 +91,14 @@ fun SavingsMakeTransferContent(
Pair(payToStepState, R.string.one),
Pair(payFromStepState, R.string.two),
Pair(amountStepState, R.string.three),
- Pair(remarkStepState, R.string.four)
+ Pair(remarkStepState, R.string.four),
)
Column(
- modifier = Modifier
+ modifier = modifier
.verticalScroll(scrollState)
.padding(horizontal = 12.dp)
- .fillMaxSize()
+ .fillMaxSize(),
) {
for (step in stepsState) {
MFStepProcess(
@@ -97,48 +106,51 @@ fun SavingsMakeTransferContent(
activateColor = Primary,
processState = step.first,
deactivateColor = DarkGray,
- isLastStep = step == stepsState.last()
- ) { modifier ->
+ isLastStep = step == stepsState.last(),
+ ) { processModifier ->
when (step.second) {
- R.string.one -> PayToStepContent(modifier = modifier,
+ R.string.one -> PayToStepContent(
+ modifier = processModifier,
processState = payToStepState,
toAccountOptions = uiData.accountOptionsTemplate.fromAccountOptions,
prefilledAccount = payToAccount,
onContinueClick = {
payToAccount = it
currentStep += 1
- }
+ },
)
- R.string.two -> PayFromStep(modifier = modifier,
+ R.string.two -> PayFromStep(
+ modifier = processModifier,
processState = payFromStepState,
fromAccountOptions = uiData.accountOptionsTemplate.fromAccountOptions,
prefilledAccount = payFromAccount,
onContinueClick = {
payFromAccount = it
currentStep += 1
- }
+ },
)
- R.string.three -> EnterAmountStep(modifier = modifier,
+ R.string.three -> EnterAmountStep(
processState = amountStepState,
- outstandingBalance = uiData.outstandingBalance,
onContinueClick = {
amount = it
currentStep += 1
- }
+ },
+ modifier = processModifier,
+ outstandingBalance = uiData.outstandingBalance,
)
R.string.four -> RemarkStep(
- modifier = modifier,
+ modifier = processModifier,
processState = remarkStepState,
onContinueClicked = {
remark = it
reviewTransfer(
- ReviewTransferPayload(payToAccount, payFromAccount, amount, remark)
+ ReviewTransferPayload(payToAccount, payFromAccount, amount, remark),
)
},
- onCancelledClicked = onCancelledClicked
+ onCancelledClicked = onCancelledClicked,
)
}
}
@@ -147,12 +159,12 @@ fun SavingsMakeTransferContent(
}
@Composable
-fun PayToStepContent(
- modifier: Modifier,
+private fun PayToStepContent(
toAccountOptions: List,
prefilledAccount: AccountOption?,
processState: StepProcessState,
onContinueClick: (AccountOption) -> Unit,
+ modifier: Modifier = Modifier,
) {
var payToAccount by rememberSaveable { mutableStateOf(prefilledAccount) }
var payToStepError by rememberSaveable { mutableStateOf(false) }
@@ -168,28 +180,31 @@ fun PayToStepContent(
onClick = { index, _ ->
payToAccount = toAccountOptions[index]
payToStepError = false
- }
+ },
)
if (processState == StepProcessState.ACTIVE) {
- Button(onClick = {
- if (payToAccount == null) payToStepError = true
- else onContinueClick(payToAccount ?: AccountOption())
- }, content = {
- Text(text = stringResource(id = R.string.continue_str))
- })
+ MifosButton(
+ textResId = R.string.continue_str,
+ onClick = {
+ if (payToAccount == null) {
+ payToStepError = true
+ } else {
+ onContinueClick(payToAccount ?: AccountOption())
+ }
+ },
+ )
}
}
}
@Composable
-fun PayFromStep(
- modifier: Modifier,
+private fun PayFromStep(
fromAccountOptions: List,
prefilledAccount: AccountOption?,
processState: StepProcessState,
- onContinueClick: (AccountOption) -> Unit
+ onContinueClick: (AccountOption) -> Unit,
+ modifier: Modifier = Modifier,
) {
-
var payFromAccount by rememberSaveable { mutableStateOf(prefilledAccount) }
var payFromError by rememberSaveable { mutableStateOf(false) }
@@ -197,14 +212,14 @@ fun PayFromStep(
Text(
text = stringResource(id = R.string.pay_from),
color = MaterialTheme.colorScheme.onSurface,
- fontWeight = FontWeight.Bold
+ fontWeight = FontWeight.Bold,
)
if (processState == StepProcessState.ACTIVE) {
MifosDropDownDoubleTextField(
optionsList = fromAccountOptions.map {
Pair(
it.accountNo ?: "",
- it.clientName ?: ""
+ it.clientName ?: "",
)
},
selectedOption = payFromAccount?.accountNo ?: "",
@@ -214,26 +229,29 @@ fun PayFromStep(
onClick = { index, _ ->
payFromAccount = fromAccountOptions[index]
payFromError = false
- }
+ },
+ )
+ MifosButton(
+ textResId = R.string.continue_str,
+ onClick = {
+ if (payFromAccount == null) {
+ payFromError = true
+ } else {
+ onContinueClick(payFromAccount ?: AccountOption())
+ }
+ },
)
- Button(onClick = {
- if (payFromAccount == null) payFromError = true
- else onContinueClick(payFromAccount ?: AccountOption())
- }, content = {
- Text(text = stringResource(id = R.string.continue_str))
- })
}
}
}
@Composable
-fun EnterAmountStep(
- modifier: Modifier,
- outstandingBalance: Double? = null,
+private fun EnterAmountStep(
processState: StepProcessState,
- onContinueClick: (String) -> Unit
+ onContinueClick: (String) -> Unit,
+ modifier: Modifier = Modifier,
+ outstandingBalance: Double? = null,
) {
- val context = LocalContext.current
var amount by remember { mutableStateOf(TextFieldValue(outstandingBalance?.toString() ?: "")) }
var amountError by rememberSaveable { mutableStateOf(null) }
var showAmountError by rememberSaveable { mutableStateOf(false) }
@@ -252,7 +270,7 @@ fun EnterAmountStep(
Text(
text = stringResource(id = R.string.amount),
color = MaterialTheme.colorScheme.onSurface,
- fontWeight = FontWeight.Bold
+ fontWeight = FontWeight.Bold,
)
if (processState == StepProcessState.ACTIVE) {
MifosOutlinedTextField(
@@ -265,25 +283,26 @@ fun EnterAmountStep(
enabled = outstandingBalance == null,
label = R.string.enter_amount,
)
- Button(
+ MifosButton(
+ textResId = R.string.continue_str,
onClick = {
- if(amountError == null) { onContinueClick(amount.text) }
- else { showAmountError = true }
+ if (amountError == null) {
+ onContinueClick(amount.text)
+ } else {
+ showAmountError = true
+ }
},
- content = {
- Text(text = stringResource(id = R.string.continue_str))
- }
)
}
}
}
@Composable
-fun RemarkStep(
- modifier: Modifier,
+private fun RemarkStep(
processState: StepProcessState,
onContinueClicked: (String) -> Unit,
- onCancelledClicked: () -> Unit = {}
+ modifier: Modifier = Modifier,
+ onCancelledClicked: () -> Unit = {},
) {
var remark by remember { mutableStateOf(TextFieldValue("")) }
var remarkError by rememberSaveable { mutableStateOf(null) }
@@ -301,7 +320,7 @@ fun RemarkStep(
Text(
text = stringResource(id = R.string.remark),
color = MaterialTheme.colorScheme.onSurface,
- fontWeight = FontWeight.Bold
+ fontWeight = FontWeight.Bold,
)
if (processState == StepProcessState.ACTIVE) {
Spacer(modifier = Modifier.height(12.dp))
@@ -311,21 +330,21 @@ fun RemarkStep(
isError = showRemarkError,
supportingText = { remarkError?.let { stringResource(id = it) } },
onValueChange = { remark = it },
- label = { Text(text = stringResource(id = R.string.remark)) }
+ label = { Text(text = stringResource(id = R.string.remark)) },
)
Spacer(modifier = Modifier.height(12.dp))
Row {
- Button(
+ MifosButton(
+ textResId = R.string.review,
onClick = {
remarkError?.let { showRemarkError = true }
?: onContinueClicked(remark.text)
},
- content = { Text(text = stringResource(id = R.string.review)) }
)
Spacer(modifier = Modifier.width(12.dp))
- OutlinedButton(
- onClick = { onCancelledClicked() },
- content = { Text(text = stringResource(id = R.string.cancel)) }
+ MifosOutlinedButton(
+ textResId = R.string.cancel,
+ onClick = onCancelledClicked,
)
}
} else {
@@ -333,20 +352,19 @@ fun RemarkStep(
text = stringResource(id = R.string.enter_remarks),
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
fontWeight = FontWeight.Bold,
- style = MaterialTheme.typography.labelMedium
+ style = MaterialTheme.typography.labelMedium,
)
}
}
}
-@Preview(showSystemUi = true)
+@DevicePreviews
@Composable
-fun SavingsMakeTransferContentPreview() {
+private fun SavingsMakeTransferContentPreview() {
MifosMobileTheme {
SavingsMakeTransferContent(
uiData = SavingsMakeTransferUiData(),
- reviewTransfer = {}
+ reviewTransfer = {},
)
}
}
-
diff --git a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_make_transfer/SavingsMakeTransferScreen.kt b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsMakeTransfer/SavingsMakeTransferScreen.kt
similarity index 65%
rename from feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_make_transfer/SavingsMakeTransferScreen.kt
rename to feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsMakeTransfer/SavingsMakeTransferScreen.kt
index 0a62d6afe..20756f820 100644
--- a/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savings_make_transfer/SavingsMakeTransferScreen.kt
+++ b/feature/savings/src/main/java/org/mifos/mobile/feature/savings/savingsMakeTransfer/SavingsMakeTransferScreen.kt
@@ -1,4 +1,13 @@
-package org.mifos.mobile.feature.savings.savings_make_transfer
+/*
+ * Copyright 2024 Mifos Initiative
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
+ */
+package org.mifos.mobile.feature.savings.savingsMakeTransfer
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -6,7 +15,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.hilt.navigation.compose.hiltViewModel
@@ -19,14 +27,16 @@ import org.mifos.mobile.core.model.entity.payload.ReviewTransferPayload
import org.mifos.mobile.core.model.enums.TransferType
import org.mifos.mobile.core.ui.component.MifosErrorComponent
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
+import org.mifos.mobile.core.ui.utils.DevicePreviews
import org.mifos.mobile.feature.savings.R
@Composable
-fun SavingsMakeTransferScreen(
- viewModel: SavingsMakeTransferViewModel = hiltViewModel(),
+internal fun SavingsMakeTransferScreen(
onCancelledClicked: () -> Unit,
navigateBack: () -> Unit,
- reviewTransfer: (ReviewTransferPayload, TransferType) -> Unit
+ reviewTransfer: (ReviewTransferPayload, TransferType) -> Unit,
+ modifier: Modifier = Modifier,
+ viewModel: SavingsMakeTransferViewModel = hiltViewModel(),
) {
val uiState = viewModel.savingsMakeTransferUiState.collectAsStateWithLifecycle()
val uiData = viewModel.savingsMakeTransferUiData.collectAsStateWithLifecycle()
@@ -36,36 +46,46 @@ fun SavingsMakeTransferScreen(
onCancelledClicked = onCancelledClicked,
uiState = uiState.value,
uiData = uiData.value,
- reviewTransfer = { reviewTransfer(it, TransferType.SELF) }
+ modifier = modifier,
+ reviewTransfer = { reviewTransfer(it, TransferType.SELF) },
)
}
@Composable
-fun SavingsMakeTransferScreen(
+private fun SavingsMakeTransferScreen(
uiState: SavingsMakeTransferUiState,
uiData: SavingsMakeTransferUiData,
- onCancelledClicked: () -> Unit = {},
navigateBack: () -> Unit,
- reviewTransfer: (ReviewTransferPayload) -> Unit
+ reviewTransfer: (ReviewTransferPayload) -> Unit,
+ modifier: Modifier = Modifier,
+ onCancelledClicked: () -> Unit = {},
) {
val context = LocalContext.current
MifosScaffold(
- topBarTitleResId = if(uiData.transferType == Constants.TRANSFER_PAY_TO) R.string.deposit
- else R.string.transfer,
+ topBarTitleResId = if (uiData.transferType == Constants.TRANSFER_PAY_TO) {
+ R.string.deposit
+ } else {
+ R.string.transfer
+ },
navigateBack = navigateBack,
+ modifier = modifier,
content = {
- Box(modifier = Modifier.padding(it).fillMaxSize()) {
+ Box(
+ modifier = Modifier
+ .padding(it)
+ .fillMaxSize(),
+ ) {
SavingsMakeTransferContent(
uiData = uiData,
+ reviewTransfer = reviewTransfer,
onCancelledClicked = onCancelledClicked,
- reviewTransfer = reviewTransfer
)
- when(uiState) {
+ when (uiState) {
is SavingsMakeTransferUiState.ShowUI -> Unit
- is SavingsMakeTransferUiState.Loading -> { MifosProgressIndicatorOverlay() }
+ is SavingsMakeTransferUiState.Loading -> MifosProgressIndicatorOverlay()
is SavingsMakeTransferUiState.Error -> {
MifosErrorComponent(
@@ -76,13 +96,12 @@ fun SavingsMakeTransferScreen(
}
}
}
- }
+ },
)
}
-
-
-class SavingsMakeTransferUiStatesPreviews : PreviewParameterProvider {
+internal class SavingsMakeTransferUiStatesPreviews :
+ PreviewParameterProvider {
override val values: Sequence
get() = sequenceOf(
SavingsMakeTransferUiState.ShowUI,
@@ -91,18 +110,19 @@ class SavingsMakeTransferUiStatesPreviews : PreviewParameterProvider = savedStateHandle.getStateFlow(
key = Constants.TRANSFER_TYPE,
- initialValue = TRANSFER_PAY_TO
+ initialValue = TRANSFER_PAY_TO,
)
private val outstandingBalance: StateFlow = savedStateHandle.getStateFlow(
key = Constants.OUTSTANDING_BALANCE,
- initialValue = null
+ initialValue = null,
).map { balanceString ->
balanceString?.toDoubleOrNull() ?: 0.0
}.stateIn(
@@ -54,16 +62,22 @@ class SavingsMakeTransferViewModel @Inject constructor(
.asResult()
.map { result ->
when (result) {
- is Result.Success -> SavingsMakeTransferUiState.ShowUI
- .also {
- _savingsMakeTransferUiData.value = _savingsMakeTransferUiData.value
- .copy(
- accountOptionsTemplate = result.data,
- transferType = transferType.value,
- outstandingBalance = if(outstandingBalance.value == 0.0) null else outstandingBalance.value,
- accountId = accountId.value
- )
- }
+ is Result.Success ->
+ SavingsMakeTransferUiState.ShowUI
+ .also {
+ _savingsMakeTransferUiData.value = _savingsMakeTransferUiData.value
+ .copy(
+ accountOptionsTemplate = result.data,
+ transferType = transferType.value,
+ outstandingBalance = if (outstandingBalance.value == 0.0) {
+ null
+ } else {
+ outstandingBalance.value
+ },
+ accountId = accountId.value,
+ )
+ }
+
is Result.Loading -> SavingsMakeTransferUiState.Loading
is Result.Error -> SavingsMakeTransferUiState.Error(result.exception.message)
}
@@ -72,21 +86,19 @@ class SavingsMakeTransferViewModel @Inject constructor(
started = SharingStarted.WhileSubscribed(5_000),
initialValue = SavingsMakeTransferUiState.Loading,
)
-
}
-sealed class SavingsMakeTransferUiState {
+internal sealed class SavingsMakeTransferUiState {
data object Loading : SavingsMakeTransferUiState()
data class Error(val errorMessage: String?) : SavingsMakeTransferUiState()
data object ShowUI : SavingsMakeTransferUiState()
}
-data class SavingsMakeTransferUiData(
+internal data class SavingsMakeTransferUiData(
var accountId: Long? = null,
var transferType: String? = null,
var outstandingBalance: Double? = null,
var accountOptionsTemplate: AccountOptionsTemplate = AccountOptionsTemplate(),
var toAccountOptionPrefilled: AccountOption? = null,
- var fromAccountOptionPrefilled: AccountOption? = null
+ var fromAccountOptionPrefilled: AccountOption? = null,
)
-
diff --git a/feature/savings/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml b/feature/savings/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml
index 7aeaab097..e0a066387 100644
--- a/feature/savings/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml
+++ b/feature/savings/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml
@@ -1,3 +1,13 @@
+
+
+
+
+
+
+
+
Active
Need Approval