diff --git a/feature/accounts/.gitignore b/feature/accounts/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/accounts/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/accounts/build.gradle.kts b/feature/accounts/build.gradle.kts
new file mode 100644
index 000000000..c01dc3616
--- /dev/null
+++ b/feature/accounts/build.gradle.kts
@@ -0,0 +1,18 @@
+plugins {
+ alias(libs.plugins.mifospay.android.feature)
+ alias(libs.plugins.mifospay.android.library.compose)
+}
+
+android {
+ namespace = "org.mifospay.feature.bank.accounts"
+}
+
+dependencies {
+ implementation(projects.core.data)
+ implementation(libs.compose.material)
+ implementation(libs.androidx.appcompat)
+
+ //Remove the following implementations after completing migration
+ implementation(projects.mifospay)
+ implementation("com.mifos.mobile:mifos-passcode:0.3.0@aar")
+}
\ No newline at end of file
diff --git a/feature/accounts/consumer-rules.pro b/feature/accounts/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/feature/accounts/proguard-rules.pro b/feature/accounts/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/feature/accounts/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/feature/accounts/src/androidTest/java/org/mifospay/feature/bank/accounts/ExampleInstrumentedTest.kt b/feature/accounts/src/androidTest/java/org/mifospay/feature/bank/accounts/ExampleInstrumentedTest.kt
new file mode 100644
index 000000000..ce5ba16b6
--- /dev/null
+++ b/feature/accounts/src/androidTest/java/org/mifospay/feature/bank/accounts/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package org.mifospay.feature.bank.accounts
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("org.mifospay.feature.bank.accounts.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/feature/accounts/src/main/AndroidManifest.xml b/feature/accounts/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..a5918e68a
--- /dev/null
+++ b/feature/accounts/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt
new file mode 100644
index 000000000..ba981a2eb
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt
@@ -0,0 +1,114 @@
+package org.mifospay.feature.bank.accounts
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.mifospay.core.model.domain.BankAccountDetails
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import java.util.Random
+import javax.inject.Inject
+
+@HiltViewModel
+class AccountViewModel @Inject constructor() : ViewModel() {
+
+ private val _bankAccountDetailsList = MutableStateFlow>(emptyList())
+ val bankAccountDetailsList: StateFlow> = _bankAccountDetailsList
+
+ private val _accountsUiState = MutableStateFlow(AccountsUiState.Loading)
+ val accountsUiState: StateFlow = _accountsUiState
+
+ init {
+ fetchLinkedAccount()
+ }
+
+ private val _isRefreshing = MutableStateFlow(false)
+ val isRefreshing: StateFlow get() = _isRefreshing.asStateFlow()
+
+ fun refresh() {
+ viewModelScope.launch {
+ _isRefreshing.emit(true)
+ fetchLinkedAccount()
+ _isRefreshing.emit(false)
+ }
+ }
+
+ private val mRandom = Random()
+
+ private fun fetchLinkedAccount() {
+ viewModelScope.launch {
+ _accountsUiState.value = AccountsUiState.Loading
+ delay(2000)
+ val linkedAccounts = fetchSampleLinkedAccounts()
+ _bankAccountDetailsList.value = linkedAccounts
+ _accountsUiState.value = if (linkedAccounts.isEmpty()) {
+ AccountsUiState.Empty
+ } else {
+ AccountsUiState.LinkedAccounts(linkedAccounts)
+ }
+ }
+ }
+
+ private fun fetchSampleLinkedAccounts(): List {
+ return listOf(
+ BankAccountDetails(
+ "SBI", "Ankur Sharma", "New Delhi",
+ mRandom.nextInt().toString() + " ", "Savings"
+ ),
+ BankAccountDetails(
+ "HDFC", "Mandeep Singh", "Uttar Pradesh",
+ mRandom.nextInt().toString() + " ", "Savings"
+ ),
+ BankAccountDetails(
+ "ANDHRA", "Rakesh anna", "Telegana",
+ mRandom.nextInt().toString() + " ", "Savings"
+ ),
+ BankAccountDetails(
+ "PNB", "luv Pro", "Gujrat",
+ mRandom.nextInt().toString() + " ", "Savings"
+ ),
+ BankAccountDetails(
+ "HDF", "Harry potter", "Hogwarts",
+ mRandom.nextInt().toString() + " ", "Savings"
+ ),
+ BankAccountDetails(
+ "GCI", "JIGME", "JAMMU",
+ mRandom.nextInt().toString() + " ", "Savings"
+ ),
+ BankAccountDetails(
+ "FCI", "NISHU BOII", "ASSAM",
+ mRandom.nextInt().toString() + " ", "Savings"
+ )
+ )
+ }
+
+ fun addBankAccount(bankAccountDetails: BankAccountDetails) {
+ viewModelScope.launch {
+ val updatedList = _bankAccountDetailsList.value.toMutableList().apply {
+ add(bankAccountDetails)
+ }
+ _bankAccountDetailsList.value = updatedList
+ _accountsUiState.value = AccountsUiState.LinkedAccounts(updatedList)
+ }
+ }
+
+ fun updateBankAccount(index: Int, bankAccountDetails: BankAccountDetails) {
+ viewModelScope.launch {
+ val updatedList = _bankAccountDetailsList.value.toMutableList().apply {
+ this[index] = bankAccountDetails
+ }
+ _bankAccountDetailsList.value = updatedList
+ _accountsUiState.value = AccountsUiState.LinkedAccounts(updatedList)
+ }
+ }
+}
+
+sealed class AccountsUiState {
+ data object Loading : AccountsUiState()
+ data object Empty : AccountsUiState()
+ data object Error : AccountsUiState()
+ data class LinkedAccounts(val linkedAccounts: List) : AccountsUiState()
+}
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsItem.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsItem.kt
new file mode 100644
index 000000000..3a732a4e9
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsItem.kt
@@ -0,0 +1,83 @@
+package org.mifospay.feature.bank.accounts
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.mifospay.core.model.domain.BankAccountDetails
+import org.mifospay.R
+import org.mifospay.core.designsystem.component.MifosCard
+import org.mifospay.core.designsystem.theme.mifosText
+import org.mifospay.core.designsystem.theme.styleMedium16sp
+
+@Composable
+fun AccountsItem(
+ bankAccountDetails: BankAccountDetails,
+ onAccountClicked: () -> Unit
+) {
+ MifosCard(
+ onClick = { onAccountClicked.invoke() },
+ colors = CardDefaults.cardColors(Color.White)
+ ) {
+ Column {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ ) {
+ Icon(
+ painter = painterResource(id = R.drawable.ic_bank),
+ contentDescription = null,
+ modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .padding(start = 16.dp, end = 16.dp)
+ .size(39.dp)
+ )
+
+ Column {
+ Text(
+ text = bankAccountDetails.accountholderName.toString(),
+ color = mifosText,
+ )
+ Text(
+ text = bankAccountDetails.bankName.toString(),
+ modifier = Modifier.padding(top = 4.dp),
+ style = styleMedium16sp.copy(mifosText)
+ )
+ }
+ Column(
+ horizontalAlignment = Alignment.End,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(
+ text = bankAccountDetails.branch.toString(),
+ modifier = Modifier.padding(16.dp),
+ fontSize = 12.sp,
+ color = mifosText
+ )
+ }
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun AccountsItemPreview() {
+ AccountsItem(
+ bankAccountDetails = BankAccountDetails("A", "B", "C"),
+ onAccountClicked = {}
+ )
+}
\ No newline at end of file
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt
new file mode 100644
index 000000000..8202a3dcb
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt
@@ -0,0 +1,236 @@
+package org.mifospay.feature.bank.accounts
+
+import android.app.Activity
+import android.content.Intent
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.Info
+import androidx.compose.material.pullrefresh.PullRefreshIndicator
+import androidx.compose.material.pullrefresh.pullRefresh
+import androidx.compose.material.pullrefresh.rememberPullRefreshState
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.mifospay.core.model.domain.BankAccountDetails
+import org.mifospay.R
+import org.mifospay.common.Constants
+import org.mifospay.core.designsystem.component.MfLoadingWheel
+import org.mifospay.core.ui.EmptyContentScreen
+import org.mifospay.core.ui.utility.AddCardChip
+import org.mifospay.feature.bank.accounts.details.BankAccountDetailActivity
+import org.mifospay.feature.bank.accounts.link.LinkBankAccountActivity
+
+@Composable
+fun AccountsScreen(
+ viewModel: AccountViewModel = hiltViewModel()
+) {
+ val accountsUiState by viewModel.accountsUiState.collectAsStateWithLifecycle()
+ val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle()
+ val bankAccountDetailsList by viewModel.bankAccountDetailsList.collectAsStateWithLifecycle()
+
+ val context = LocalContext.current
+ val updateBankAccountLauncher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.StartActivityForResult()
+ ) { result ->
+ if (result.resultCode == Activity.RESULT_OK) {
+ val bundle = result.data?.extras
+ if (bundle != null) {
+ val bankAccountDetails = bundle.getParcelable(Constants.UPDATED_BANK_ACCOUNT)
+ val index = bundle.getInt(Constants.INDEX)
+ if (bankAccountDetails != null) {
+ viewModel.updateBankAccount(index, bankAccountDetails)
+ }
+ }
+ }
+ }
+
+ AccountScreen(
+ accountsUiState = accountsUiState,
+ onAddAccount = {
+ val intent = Intent(context, LinkBankAccountActivity::class.java)
+ context.startActivity(intent)
+ },
+ bankAccountDetailsList = bankAccountDetailsList,
+ isRefreshing = isRefreshing,
+ onRefresh = {
+ viewModel.refresh()
+ },
+ onUpdateAccount = { bankAccountDetails, index ->
+ val intent = Intent(context, BankAccountDetailActivity::class.java).apply {
+ putExtra(Constants.BANK_ACCOUNT_DETAILS, bankAccountDetails)
+ putExtra(Constants.INDEX, index)
+ }
+ updateBankAccountLauncher.launch(intent)
+ }
+ )
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun AccountScreen(
+ accountsUiState: AccountsUiState,
+ onAddAccount: () -> Unit,
+ bankAccountDetailsList: List,
+ isRefreshing: Boolean,
+ onRefresh: () -> Unit,
+ onUpdateAccount: (BankAccountDetails, Int) -> Unit
+) {
+ val pullRefreshState = rememberPullRefreshState(isRefreshing, onRefresh)
+ Box(Modifier.pullRefresh(pullRefreshState)) {
+ Column(modifier = Modifier.fillMaxSize()) {
+ when (accountsUiState) {
+ AccountsUiState.Empty -> {
+ NoLinkedAccountsScreen { onAddAccount.invoke() }
+ }
+
+ AccountsUiState.Error -> {
+ EmptyContentScreen(
+ modifier = Modifier,
+ title = stringResource(id = R.string.error_oops),
+ subTitle = stringResource(id = R.string.unexpected_error_subtitle),
+ iconTint = Color.Black,
+ iconImageVector = Icons.Rounded.Info
+ )
+ }
+
+ is AccountsUiState.LinkedAccounts -> {
+ LazyColumn(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxSize()
+ ) {
+ item {
+ Text(
+ text = stringResource(id = R.string.linked_bank_account),
+ fontSize = 16.sp,
+ color = colorResource(id = R.color.colorTextPrimary),
+ modifier = Modifier.padding(top = 48.dp, start = 24.dp)
+ )
+ }
+ items(bankAccountDetailsList) { bankAccountDetails ->
+ val index = bankAccountDetailsList.indexOf(bankAccountDetails)
+ AccountsItem(
+ bankAccountDetails = bankAccountDetails,
+ onAccountClicked = {
+ onUpdateAccount(bankAccountDetails, index)
+ }
+ )
+ HorizontalDivider(
+ modifier = Modifier.padding(8.dp)
+ )
+ }
+ item {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp)
+ .background(color = Color.White)
+ ) {
+ AddCardChip(
+ modifier = Modifier.align(Alignment.Center),
+ onAddBtn = onAddAccount,
+ text = R.string.add_account,
+ btnText = R.string.add_cards
+ )
+ }
+ }
+ }
+ }
+
+ AccountsUiState.Loading -> {
+ MfLoadingWheel(
+ contentDesc = stringResource(R.string.loading),
+ backgroundColor = Color.White
+ )
+ }
+
+ else -> {}
+ }
+ }
+ PullRefreshIndicator(
+ refreshing = isRefreshing,
+ state = pullRefreshState,
+ modifier = Modifier.align(Alignment.TopCenter)
+ )
+ }
+}
+
+@Composable
+fun NoLinkedAccountsScreen(onAddBtn: () -> Unit) {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(text = stringResource(R.string.no_linked_bank_accounts))
+ AddCardChip(
+ modifier = Modifier,
+ onAddBtn = onAddBtn,
+ text = R.string.add_account,
+ btnText = R.string.add_cards
+ )
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun AccountScreenLoadingPreview() {
+ AccountScreen(accountsUiState = AccountsUiState.Loading, {}, emptyList(), false, {}, { _, _ -> })
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun AccountEmptyScreenPreview() {
+ AccountScreen(accountsUiState = AccountsUiState.Empty, {}, emptyList(), false, {}, { _, _ -> })
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun AccountListScreenPreview() {
+ AccountScreen(
+ accountsUiState = AccountsUiState.LinkedAccounts(sampleLinkedAccount),
+ {},
+ sampleLinkedAccount,
+ false,
+ {},
+ { _, _ -> }
+ )
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun AccountErrorScreenPreview() {
+ AccountScreen(accountsUiState = AccountsUiState.Error, {}, emptyList(), false, {}, { _, _ -> })
+}
+
+val sampleLinkedAccount = List(10) {
+ BankAccountDetails(
+ "SBI", "Ankur Sharma", "New Delhi",
+ "XXXXXXXX9990XXX " + " ", "Savings"
+ )
+}
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/details/BankAccountDetailActivity.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/details/BankAccountDetailActivity.kt
new file mode 100644
index 000000000..b22b12c29
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/details/BankAccountDetailActivity.kt
@@ -0,0 +1,81 @@
+package org.mifospay.feature.bank.accounts.details
+
+import android.content.Intent
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import com.mifospay.core.model.domain.BankAccountDetails
+import dagger.hilt.android.AndroidEntryPoint
+import org.mifospay.bank.setupUpi.ui.SetupUpiPinActivity
+import org.mifospay.base.BaseActivity
+import org.mifospay.common.Constants
+import org.mifospay.theme.MifosTheme
+import org.mifospay.utils.Toaster
+
+@AndroidEntryPoint
+class BankAccountDetailActivity : BaseActivity() {
+
+ private lateinit var bankAccountDetails: BankAccountDetails
+ private var index = 0
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ bankAccountDetails = intent.extras?.getParcelable(Constants.BANK_ACCOUNT_DETAILS)!!
+ index = intent.extras!!.getInt(Constants.INDEX)
+
+ setContent {
+ MifosTheme {
+ BankAccountDetailScreen(
+ bankAccountDetails = bankAccountDetails,
+ onSetupUpiPin = { onSetupUpiPinClicked() },
+ onChangeUpiPin = { onChangeUpiPinClicked() },
+ onForgotUpiPin = { onForgotUpiPinClicked() },
+ navigateBack = { onBackPressed() }
+ )
+ }
+ }
+ }
+
+ private fun onSetupUpiPinClicked() {
+ startSetupActivity(Constants.SETUP, index)
+ }
+
+ private fun onChangeUpiPinClicked() {
+ if (bankAccountDetails.isUpiEnabled) {
+ startSetupActivity(Constants.CHANGE, index)
+ } else {
+ showToast(Constants.SETUP_UPI_PIN)
+ }
+ }
+
+ private fun onForgotUpiPinClicked() {
+ if (bankAccountDetails.isUpiEnabled) {
+ startSetupActivity(Constants.FORGOT, index)
+ } else {
+ showToast(Constants.SETUP_UPI_PIN)
+ }
+ }
+
+ private fun startSetupActivity(type: String, index: Int) {
+ val intent = Intent(this@BankAccountDetailActivity, SetupUpiPinActivity::class.java)
+ intent.putExtra(Constants.BANK_ACCOUNT_DETAILS, bankAccountDetails)
+ intent.putExtra(Constants.TYPE, type)
+ intent.putExtra(Constants.INDEX, index)
+ startActivityForResult(intent, SETUP_UPI_REQUEST_CODE)
+ }
+
+ private fun showToast(message: String?) {
+ Toaster.showToast(this, message)
+ }
+
+ override fun onBackPressed() {
+ val intent = Intent()
+ intent.putExtra(Constants.UPDATED_BANK_ACCOUNT, bankAccountDetails)
+ intent.putExtra(Constants.INDEX, index)
+ setResult(RESULT_OK, intent)
+ super.onBackPressed()
+ }
+
+ companion object {
+ const val SETUP_UPI_REQUEST_CODE = 2
+ }
+}
\ No newline at end of file
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/details/BankAccountDetailScreen.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/details/BankAccountDetailScreen.kt
new file mode 100644
index 000000000..5cf7956cb
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/details/BankAccountDetailScreen.kt
@@ -0,0 +1,220 @@
+package org.mifospay.feature.bank.accounts.details
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ChevronRight
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.mifospay.core.model.domain.BankAccountDetails
+import org.mifospay.R
+import org.mifospay.core.designsystem.component.MifosTopBar
+import org.mifospay.core.designsystem.theme.mifosText
+import org.mifospay.core.designsystem.theme.styleMedium16sp
+
+@Composable
+fun BankAccountDetailScreen(
+ bankAccountDetails: BankAccountDetails,
+ onSetupUpiPin: () -> Unit,
+ onChangeUpiPin: () -> Unit,
+ onForgotUpiPin: () -> Unit,
+ navigateBack: () -> Unit
+) {
+ BankAccountDetailScreen(
+ bankName = bankAccountDetails.bankName.toString(),
+ accountHolderName = bankAccountDetails.accountholderName.toString(),
+ branchName = bankAccountDetails.branch.toString(),
+ ifsc = bankAccountDetails.ifsc.toString(),
+ type = bankAccountDetails.type.toString(),
+ isUpiEnabled = bankAccountDetails.isUpiEnabled,
+ onSetupUpiPin = onSetupUpiPin,
+ onChangeUpiPin = onChangeUpiPin,
+ onForgotUpiPin = onForgotUpiPin,
+ navigateBack = navigateBack
+ )
+}
+
+@Composable
+fun BankAccountDetailScreen(
+ bankName: String,
+ accountHolderName: String,
+ branchName: String,
+ ifsc: String,
+ type: String,
+ isUpiEnabled: Boolean,
+ onSetupUpiPin: () -> Unit,
+ onChangeUpiPin: () -> Unit,
+ onForgotUpiPin: () -> Unit,
+ navigateBack: () -> Unit
+) {
+ Column(modifier = Modifier.fillMaxSize()) {
+ MifosTopBar(topBarTitle = R.string.bank_account_details) { navigateBack.invoke() }
+ Column(
+ modifier = Modifier
+ .padding(20.dp)
+ .border(2.dp, Color.Black)
+ .padding(20.dp)
+ ) {
+ BankAccountDetailRows(
+ modifier = Modifier.fillMaxWidth(),
+ detail = R.string.bank_name,
+ detailValue = bankName
+ )
+ BankAccountDetailRows(
+ modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
+ detail = R.string.ac_holder_name,
+ detailValue = accountHolderName
+ )
+ BankAccountDetailRows(
+ modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
+ detail = R.string.branch_name,
+ detailValue = branchName
+ )
+ BankAccountDetailRows(
+ modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
+ detail = R.string.ifsc,
+ detailValue = ifsc
+ )
+ BankAccountDetailRows(
+ modifier = Modifier.fillMaxWidth().padding(top = 10.dp),
+ detail = R.string.type,
+ detailValue = type
+ )
+ }
+
+ Row(
+ modifier = Modifier.fillMaxWidth().padding(20.dp),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+
+ BankAccountDetailButton(
+ btnText = R.string.setup_upi,
+ onClick = { onSetupUpiPin.invoke() },
+ isUpiEnabled = !isUpiEnabled,
+ hasTrailingIcon = false
+ )
+
+ BankAccountDetailButton(
+ btnText = R.string.delete_bank,
+ onClick = {},
+ isUpiEnabled = !isUpiEnabled
+ )
+ }
+
+ Column(
+ modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(20.dp)
+ ) {
+ BankAccountDetailButton(
+ btnText = R.string.change_upi_pin,
+ onClick = { onChangeUpiPin.invoke() },
+ isUpiEnabled = isUpiEnabled,
+ modifier = Modifier.fillMaxWidth()
+ )
+ BankAccountDetailButton(
+ btnText = R.string.forgot_upi_pin,
+ onClick = { onForgotUpiPin.invoke() },
+ isUpiEnabled = isUpiEnabled,
+ modifier = Modifier.fillMaxWidth()
+ )
+ }
+ }
+}
+
+@Composable
+fun BankAccountDetailRows(
+ modifier: Modifier, detail: Int, detailValue: String
+) {
+ Row(
+ modifier = modifier,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = detail), modifier = Modifier.padding(end = 10.dp)
+ )
+ Text(text = detailValue, style = styleMedium16sp)
+ }
+}
+
+@Composable
+fun BankAccountDetailButton(
+ modifier: Modifier = Modifier,
+ btnText: Int,
+ onClick: () -> Unit,
+ isUpiEnabled: Boolean,
+ hasTrailingIcon: Boolean = false
+) {
+ if (isUpiEnabled) {
+ Button(
+ onClick = { onClick.invoke() },
+ colors = ButtonDefaults.buttonColors(Color.White),
+ modifier = modifier
+ .padding(start = 20.dp, end = 20.dp),
+ contentPadding = PaddingValues(20.dp),
+ border = BorderStroke(2.dp, Color.Black)
+ ) {
+ Row(
+ modifier = modifier,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = stringResource(id = btnText),
+ style = TextStyle(color = mifosText, fontSize = 18.sp)
+ )
+ if (hasTrailingIcon) {
+ Icon(
+ imageVector = Icons.Filled.ChevronRight,
+ contentDescription = null,
+ tint = Color.Black
+ )
+ }
+ }
+ }
+ }
+}
+
+
+@Preview(showBackground = true)
+@Composable
+private fun BankAccountDetailUpiDisabledPreview() {
+ BankAccountDetailScreen("Mifos Bank",
+ "Mifos Account Holder",
+ "Mifos Branch",
+ "IFSC",
+ "type",
+ false,
+ {}, {}, {}, {}
+ )
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun BankAccountDetailUpiEnabledPreview() {
+ BankAccountDetailScreen("Mifos Bank",
+ "Mifos Account Holder",
+ "Mifos Branch",
+ "IFSC",
+ "type",
+ true,
+ {}, {}, {}, {}
+ )
+}
\ No newline at end of file
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountActivity.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountActivity.kt
new file mode 100644
index 000000000..a81f92063
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountActivity.kt
@@ -0,0 +1,23 @@
+package org.mifospay.feature.bank.accounts.link
+
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import androidx.appcompat.app.AppCompatActivity
+import dagger.hilt.android.AndroidEntryPoint
+import org.mifospay.theme.MifosTheme
+
+
+@AndroidEntryPoint
+class LinkBankAccountActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ MifosTheme {
+ LinkBankAccountRoute(
+ onBackClick = { finish() }
+ )
+ }
+ }
+ }
+}
+
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt
new file mode 100644
index 000000000..00d3d2eb3
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt
@@ -0,0 +1,322 @@
+package org.mifospay.feature.bank.accounts.link
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ExperimentalLayoutApi
+import androidx.compose.foundation.layout.FlowColumn
+import androidx.compose.foundation.layout.FlowRow
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+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.foundation.layout.size
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Search
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import org.mifospay.R
+import org.mifospay.bank.choose_sim.ChooseSimDialogSheet
+import org.mifospay.core.designsystem.component.MfLoadingWheel
+import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel
+import org.mifospay.core.designsystem.component.MifosCard
+import org.mifospay.core.designsystem.component.MifosOutlinedTextField
+import org.mifospay.core.designsystem.component.MifosTopAppBar
+import org.mifospay.core.designsystem.icon.MifosIcons
+import org.mifospay.domain.model.Bank
+import org.mifospay.domain.model.BankType
+import org.mifospay.theme.MifosTheme
+import org.mifospay.core.ui.DevicePreviews
+
+
+@Composable
+fun LinkBankAccountRoute(
+ viewModel: LinkBankAccountViewModel = hiltViewModel(),
+ onBackClick: () -> Unit
+) {
+ val bankUiState by viewModel.bankListUiState.collectAsStateWithLifecycle()
+ var showSimBottomSheet by rememberSaveable { mutableStateOf(false) }
+ var showOverlyProgressBar by rememberSaveable { mutableStateOf(false) }
+
+ if (showSimBottomSheet) {
+ ChooseSimDialogSheet { selectedSim ->
+ showSimBottomSheet = false
+ if (selectedSim != -1) {
+ showOverlyProgressBar = true
+ viewModel.fetchBankAccountDetails {
+ showOverlyProgressBar = false
+ onBackClick()
+ }
+ }
+ }
+ }
+
+ LinkBankAccountScreen(
+ bankUiState = bankUiState,
+ showOverlyProgressBar = showOverlyProgressBar,
+ onBankSearch = { query ->
+ viewModel.updateSearchQuery(query)
+ },
+ onBankSelected = {
+ viewModel.updateSelectedBank(it)
+ showSimBottomSheet = true
+ },
+ onBackClick = onBackClick
+ )
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun LinkBankAccountScreen(
+ bankUiState: BankUiState,
+ showOverlyProgressBar: Boolean,
+ onBankSearch: (String) -> Unit,
+ onBankSelected: (Bank) -> Unit,
+ onBackClick: () -> Unit
+) {
+
+ Scaffold(
+ modifier = Modifier.background(color = Color.White),
+ topBar = {
+ MifosTopAppBar(
+ titleRes = R.string.link_bank_account,
+ navigationIcon = MifosIcons.Back,
+ navigationIconContentDescription = "Back icon",
+ onNavigationClick = onBackClick,
+ colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
+ containerColor = Color.White,
+ ),
+ )
+ }) { paddingValues ->
+ Box(
+ modifier = Modifier.padding(paddingValues)
+ ) {
+ when (bankUiState) {
+ is BankUiState.Loading -> {
+ MfLoadingWheel(
+ contentDesc = stringResource(R.string.loading),
+ backgroundColor = Color.White
+ )
+ }
+
+ is BankUiState.Success -> {
+ BankListScreenContent(
+ banks = bankUiState.banks,
+ onBankSearch = onBankSearch,
+ onBankSelected = onBankSelected
+ )
+ }
+ }
+
+ if (showOverlyProgressBar) {
+ MfOverlayLoadingWheel()
+ }
+ }
+ }
+}
+
+@Composable
+fun BankListScreenContent(
+ banks: List,
+ onBankSearch: (String) -> Unit,
+ onBankSelected: (Bank) -> Unit
+) {
+ var searchQuery by rememberSaveable { mutableStateOf("") }
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(color = Color.White)
+ .verticalScroll(rememberScrollState())
+ ) {
+ MifosOutlinedTextField(modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp),
+ value = searchQuery,
+ onValueChange = {
+ searchQuery = it
+ onBankSearch(it)
+ },
+ label = R.string.search,
+ trailingIcon = {
+ Icon(imageVector = Icons.Filled.Search, contentDescription = null)
+ })
+
+ if (searchQuery.isBlank()) {
+ Spacer(modifier = Modifier.height(24.dp))
+ Text(
+ text = stringResource(id = R.string.popular_banks),
+ style = TextStyle(Color.Black, fontWeight = FontWeight.Medium),
+ modifier = Modifier.padding(start = 16.dp)
+ )
+ Spacer(modifier = Modifier.height(12.dp))
+ PopularBankGridBody(
+ banks = banks.filter { it.bankType == BankType.POPULAR },
+ onBankSelected = onBankSelected
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+ Text(
+ text = stringResource(id = R.string.other_banks),
+ style = TextStyle(Color.Black, fontWeight = FontWeight.Medium),
+ modifier = Modifier.padding(start = 16.dp)
+ )
+ Spacer(modifier = Modifier.height(12.dp))
+ }
+
+ BankListBody(
+ banks = if (searchQuery.isBlank()) {
+ banks.filter { it.bankType == BankType.OTHER }
+ } else banks,
+ onBankSelected = onBankSelected
+ )
+ }
+}
+
+@OptIn(ExperimentalLayoutApi::class)
+@Composable
+fun PopularBankGridBody(
+ banks: List,
+ onBankSelected: (Bank) -> Unit
+) {
+ MifosCard(
+ modifier = Modifier,
+ shape = RoundedCornerShape(0.dp),
+ elevation = 2.dp,
+ colors = CardDefaults.cardColors(Color.White)
+ ) {
+ FlowRow(
+ modifier = Modifier,
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ maxItemsInEachRow = 3
+ ) {
+ banks.forEach {
+ PopularBankItemBody(
+ modifier = Modifier.weight(1f),
+ bank = it,
+ onBankSelected = onBankSelected
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun PopularBankItemBody(
+ modifier: Modifier,
+ bank: Bank,
+ onBankSelected: (Bank) -> Unit
+) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center,
+ modifier = modifier
+ .fillMaxSize()
+ .clickable {
+ onBankSelected(bank)
+ },
+ ) {
+ Image(
+ modifier = Modifier
+ .size(58.dp)
+ .padding(bottom = 4.dp, top = 16.dp),
+ painter = painterResource(id = bank.image),
+ contentDescription = bank.name,
+ )
+ Text(
+ text = bank.name,
+ style = MaterialTheme.typography.bodyMedium,
+ modifier = Modifier.padding(top = 4.dp, bottom = 16.dp)
+ )
+ }
+}
+
+@OptIn(ExperimentalLayoutApi::class)
+@Composable
+fun BankListBody(
+ banks: List,
+ onBankSelected: (Bank) -> Unit
+) {
+ FlowColumn {
+ banks.forEach { bank ->
+ BankListItemBody(bank = bank, onBankSelected = onBankSelected)
+ }
+ }
+}
+
+@Composable
+fun BankListItemBody(
+ bank: Bank,
+ onBankSelected: (Bank) -> Unit
+) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .clickable { onBankSelected(bank) }
+ ) {
+ HorizontalDivider()
+ Row(
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 24.dp, top = 8.dp, bottom = 8.dp)
+ ) {
+ Image(
+ modifier = Modifier.size(32.dp),
+ painter = painterResource(id = bank.image),
+ contentDescription = bank.name,
+ )
+ Text(
+ modifier = Modifier.padding(start = 16.dp, end = 16.dp),
+ text = bank.name, style = TextStyle(fontSize = 14.sp)
+ )
+ }
+ }
+}
+
+@DevicePreviews
+@Composable
+private fun LinkBankAccountScreenPreview(
+ @PreviewParameter(LinkBankUiStatePreviewParameterProvider::class)
+ bankUiState: BankUiState,
+) {
+ MifosTheme {
+ LinkBankAccountScreen(
+ bankUiState = bankUiState,
+ showOverlyProgressBar = false,
+ onBankSelected = { },
+ onBankSearch = { },
+ onBackClick = { }
+ )
+ }
+}
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt
new file mode 100644
index 000000000..2107c0562
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt
@@ -0,0 +1,97 @@
+package org.mifospay.feature.bank.accounts.link
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.mifospay.core.model.domain.BankAccountDetails
+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.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.update
+import org.mifospay.R
+import org.mifospay.core.data.repository.local.MifosLocalAssetRepository
+import org.mifospay.domain.model.Bank
+import org.mifospay.domain.model.BankType
+import java.util.Random
+import javax.inject.Inject
+
+@HiltViewModel
+class LinkBankAccountViewModel @Inject constructor(
+ localAssetRepository: MifosLocalAssetRepository
+) : ViewModel() {
+
+ private val _searchQuery = MutableStateFlow("")
+ private var selectedBank by mutableStateOf(null)
+
+ private val _bankAccountDetails: MutableStateFlow = MutableStateFlow(null)
+ val bankAccountDetails: StateFlow = _bankAccountDetails.asStateFlow()
+
+ fun updateSearchQuery(query: String) {
+ _searchQuery.update { query }
+ }
+
+ fun updateSelectedBank(bank: Bank) {
+ selectedBank = bank
+ }
+
+ val bankListUiState: StateFlow = combine(
+ _searchQuery,
+ localAssetRepository.getBanks(),
+ ::Pair
+ ).map { searchQueryAndBanks ->
+ val searchQuery = searchQueryAndBanks.first
+ val localBanks = searchQueryAndBanks.second.map {
+ Bank(it, R.drawable.ic_bank, BankType.OTHER)
+ }
+ val banks = ArrayList().apply {
+ addAll(popularBankList())
+ addAll(localBanks)
+ }.distinctBy { it.name }
+ BankUiState.Success(
+ banks.filter { it.name.contains(searchQuery.lowercase(), ignoreCase = true) }
+ )
+ }.stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.WhileSubscribed(5_000),
+ initialValue = BankUiState.Loading,
+ )
+
+ private fun popularBankList(): List {
+ return listOf(
+ Bank("RBL Bank", R.drawable.logo_rbl, BankType.POPULAR),
+ Bank("SBI Bank", R.drawable.logo_sbi, BankType.POPULAR),
+ Bank("PNB Bank", R.drawable.logo_pnb, BankType.POPULAR),
+ Bank("HDFC Bank", R.drawable.logo_hdfc, BankType.POPULAR),
+ Bank("ICICI Bank", R.drawable.logo_icici, BankType.POPULAR),
+ Bank("AXIS Bank", R.drawable.logo_axis, BankType.POPULAR)
+ )
+ }
+
+ fun fetchBankAccountDetails(onBankDetailsSuccess: () -> Unit) {
+ // TODO:: UPI API implement, Implement with real API,
+ // It revert back to Account Screen after successful BankAccount Add
+ _bankAccountDetails.update {
+ BankAccountDetails(
+ selectedBank?.name, "Ankur Sharma", "New Delhi",
+ mRandom.nextInt().toString() + " ", "Savings"
+ )
+ }
+ onBankDetailsSuccess.invoke()
+ }
+
+ companion object {
+ private val mRandom = Random()
+ }
+}
+
+sealed interface BankUiState {
+ data class Success(val banks: List = emptyList()) : BankUiState
+ data object Loading : BankUiState
+}
diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankUiStatePreviewParameterProvider.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankUiStatePreviewParameterProvider.kt
new file mode 100644
index 000000000..3886db795
--- /dev/null
+++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankUiStatePreviewParameterProvider.kt
@@ -0,0 +1,25 @@
+package org.mifospay.feature.bank.accounts.link
+
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import org.mifospay.R
+import org.mifospay.domain.model.Bank
+import org.mifospay.domain.model.BankType
+
+class LinkBankUiStatePreviewParameterProvider : PreviewParameterProvider {
+
+ val banks = ArrayList().apply {
+ add(Bank("RBL Bank", R.drawable.logo_rbl, BankType.POPULAR))
+ add(Bank("SBI Bank", R.drawable.logo_sbi, BankType.POPULAR))
+ add(Bank("PNB Bank", R.drawable.logo_pnb, BankType.POPULAR))
+ add(Bank("HDFC Bank", R.drawable.logo_hdfc, BankType.POPULAR))
+ add(Bank("ICICI Bank", R.drawable.logo_icici, BankType.POPULAR))
+ add(Bank("AXIS Bank", R.drawable.logo_axis, BankType.POPULAR))
+ add(Bank("HDFC Bank", R.drawable.ic_bank, BankType.OTHER))
+ add(Bank("ICICI Bank", R.drawable.ic_bank, BankType.OTHER))
+ add(Bank("AXIS Bank", R.drawable.ic_bank, BankType.OTHER))
+ }
+
+ override val values: Sequence = sequenceOf(
+ BankUiState.Success(banks = banks)
+ )
+}
\ No newline at end of file
diff --git a/feature/accounts/src/test/java/org/mifospay/feature/bank/accounts/ExampleUnitTest.kt b/feature/accounts/src/test/java/org/mifospay/feature/bank/accounts/ExampleUnitTest.kt
new file mode 100644
index 000000000..0bb0f96e9
--- /dev/null
+++ b/feature/accounts/src/test/java/org/mifospay/feature/bank/accounts/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package org.mifospay.feature.bank.accounts
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 454b4fd51..b8e5231aa 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -48,5 +48,6 @@ include(":feature:invoices")
include(":feature:invoices")
include(":feature:settings")
include(":feature:profile")
+include(":feature:accounts")
include(":feature:standing-instruction")
include(":feature:payments")