diff --git a/feature/make-transfer/src/androidTest/java/org/mifospay/feature/make/transfer/ExampleInstrumentedTest.kt b/feature/make-transfer/src/androidTest/java/org/mifospay/feature/make/transfer/ExampleInstrumentedTest.kt
deleted file mode 100644
index 0d13a07f0..000000000
--- a/feature/make-transfer/src/androidTest/java/org/mifospay/feature/make/transfer/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.mifospay.feature.make.transfer
-
-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.make.transfer", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt
index b8fa36787..379ea1142 100644
--- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt
+++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt
@@ -44,7 +44,8 @@ import org.mifospay.core.designsystem.component.MifosOverlayLoadingWheel
@Composable
fun MakeTransferScreenRoute(
- viewModel: MakeTransferViewModel = hiltViewModel()
+ viewModel: MakeTransferViewModel = hiltViewModel(),
+ onDismiss: () -> Unit
) {
val fetchPayeeClient by viewModel.fetchPayeeClient.collectAsStateWithLifecycle()
val makeTransferState by viewModel.makeTransferState.collectAsStateWithLifecycle()
@@ -58,7 +59,8 @@ fun MakeTransferScreenRoute(
toClientId,
transferAmount
)
- }
+ },
+ onDismiss = onDismiss
)
}
@@ -67,6 +69,7 @@ fun MakeTransferScreen(
uiState: MakeTransferState,
showTransactionStatus: ShowTransactionStatus,
makeTransfer: (Long, Double) -> Unit,
+ onDismiss: () -> Unit
) {
val context = LocalContext.current
when (uiState) {
@@ -97,7 +100,8 @@ fun MakeTransferScreen(
externalId,
transferAmount,
showTransactionStatus,
- makeTransfer = makeTransfer
+ makeTransfer = makeTransfer,
+ onDismiss = onDismiss
)
}
}
@@ -113,6 +117,7 @@ fun MakeTransferBottomSheetContent(
transferAmount: Double,
showTransactionStatus: ShowTransactionStatus,
makeTransfer: (Long, Double) -> Unit,
+ onDismiss: () -> Unit
) {
val sheetState = rememberModalBottomSheetState()
@@ -125,6 +130,7 @@ fun MakeTransferBottomSheetContent(
sheetState = sheetState,
onDismissRequest = {
showBottomSheet = false
+ onDismiss.invoke()
},
dragHandle = { BottomSheetDefaults.DragHandle() },
) {
@@ -340,7 +346,8 @@ fun PreviewWithMakeTransferContentLoading() {
showSuccessStatus = false,
showErrorStatus = false
),
- makeTransfer = { _, _ -> }
+ makeTransfer = { _, _ -> },
+ onDismiss = { }
)
}
@@ -359,7 +366,8 @@ fun PreviewWithMakeTransferContentSuccess() {
showSuccessStatus = false,
showErrorStatus = false
),
- makeTransfer = { _, _ -> }
+ makeTransfer = { _, _ -> },
+ onDismiss = { }
)
}
@@ -391,7 +399,8 @@ fun PreviewMakeTransferBottomSheetContent() {
showSuccessStatus = false,
showErrorStatus = false
),
- makeTransfer = { _, _ -> }
+ makeTransfer = { _, _ -> },
+ onDismiss = { }
)
}
@@ -404,7 +413,8 @@ fun PreviewWithMakeTransferContentError() {
showSuccessStatus = false,
showErrorStatus = false
),
- makeTransfer = { _, _ -> }
+ makeTransfer = { _, _ -> },
+ onDismiss = { }
)
}
diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt
index 2e3ff2392..0c70e60e6 100644
--- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt
+++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt
@@ -30,7 +30,9 @@ fun NavController.navigateToMakeTransferScreen(
navigate(route, navOptions)
}
-fun NavGraphBuilder.makeTransferScreen() {
+fun NavGraphBuilder.makeTransferScreen(
+ onDismiss: () -> Unit
+) {
composable(
route = MAKE_TRANSFER_ROUTE,
arguments = listOf(
@@ -46,6 +48,8 @@ fun NavGraphBuilder.makeTransferScreen() {
}
)
) {
- MakeTransferScreenRoute()
+ MakeTransferScreenRoute(
+ onDismiss = onDismiss
+ )
}
}
diff --git a/feature/send-money/.gitignore b/feature/send-money/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/feature/send-money/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/feature/send-money/build.gradle.kts b/feature/send-money/build.gradle.kts
new file mode 100644
index 000000000..4605e59c2
--- /dev/null
+++ b/feature/send-money/build.gradle.kts
@@ -0,0 +1,19 @@
+plugins {
+ alias(libs.plugins.mifospay.android.feature)
+ alias(libs.plugins.mifospay.android.library.compose)
+}
+
+android {
+ namespace = "org.mifospay.feature.send.money"
+}
+
+dependencies {
+ implementation(projects.core.data)
+
+ // we need it for country picker library
+ implementation("androidx.compose.material:material:1.6.0")
+ implementation(libs.compose.country.code.picker) // remove after moving auth code to module
+
+ // Google Bar code scanner
+ implementation(libs.google.play.services.code.scanner)
+}
diff --git a/feature/send-money/src/main/AndroidManifest.xml b/feature/send-money/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..8072ee00d
--- /dev/null
+++ b/feature/send-money/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt
new file mode 100644
index 000000000..2ac79d260
--- /dev/null
+++ b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt
@@ -0,0 +1,97 @@
+package org.mifospay.feature.send.money
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import org.mifospay.core.data.base.UseCase
+import org.mifospay.core.data.base.UseCaseHandler
+import org.mifospay.core.data.domain.usecase.account.FetchAccount
+import org.mifospay.core.data.repository.local.LocalRepository
+import javax.inject.Inject
+
+@HiltViewModel
+class SendPaymentViewModel @Inject constructor(
+ private val useCaseHandler: UseCaseHandler,
+ private val localRepository: LocalRepository,
+ private val fetchAccount: FetchAccount
+) : ViewModel() {
+
+ private val _showProgress = MutableStateFlow(false)
+ val showProgress: StateFlow = _showProgress
+
+ private val _vpa = MutableStateFlow("")
+ val vpa: StateFlow = _vpa
+
+ private val _mobile = MutableStateFlow("")
+ val mobile: StateFlow = _mobile
+
+ init {
+ fetchVpa()
+ fetchMobile()
+ }
+
+ fun updateProgressState(isVisible: Boolean) {
+ _showProgress.update { isVisible }
+ }
+
+ private fun fetchVpa() {
+ viewModelScope.launch {
+ _vpa.value = localRepository.clientDetails.externalId.toString()
+ }
+ }
+
+ private fun fetchMobile() {
+ viewModelScope.launch {
+ _mobile.value = localRepository.preferencesHelper.mobile.toString()
+ }
+ }
+
+ fun checkSelfTransfer(
+ selfVpa: String?,
+ selfMobile: String?,
+ externalIdOrMobile: String?,
+ sendMethodType: SendMethodType,
+ ): Boolean {
+ return when (sendMethodType) {
+ SendMethodType.VPA -> {
+ selfVpa.takeIf { !it.isNullOrEmpty() }?.let { it == externalIdOrMobile } ?: false
+ }
+
+ SendMethodType.MOBILE -> {
+ selfMobile.takeIf { !it.isNullOrEmpty() }?.let { it == externalIdOrMobile } ?: false
+ }
+ }
+ }
+
+ fun checkBalanceAvailabilityAndTransfer(
+ externalId: String?,
+ transferAmount: Double,
+ onAnyError: (Int) -> Unit,
+ proceedWithTransferFlow: (String, Double) -> Unit
+ ) {
+ updateProgressState(true)
+ useCaseHandler.execute(fetchAccount,
+ FetchAccount.RequestValues(localRepository.clientDetails.clientId),
+ object : UseCase.UseCaseCallback {
+ override fun onSuccess(response: FetchAccount.ResponseValue) {
+ updateProgressState(false)
+ if (transferAmount > response.account.balance) {
+ onAnyError(R.string.insufficient_balance)
+ } else {
+ if (externalId != null) {
+ proceedWithTransferFlow(externalId, transferAmount)
+ }
+ }
+ }
+
+ override fun onError(message: String) {
+ updateProgressState(false)
+ onAnyError.invoke(R.string.error_fetching_balance)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt
new file mode 100644
index 000000000..6f9c985ff
--- /dev/null
+++ b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt
@@ -0,0 +1,388 @@
+package org.mifospay.feature.send.money
+
+import android.content.Context
+import android.net.Uri
+import android.provider.ContactsContract
+import android.util.Log
+import android.widget.Toast
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+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.width
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material.TextFieldDefaults
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.QrCode2
+import androidx.compose.material3.Icon
+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
+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.platform.LocalContext
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.KeyboardType
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.google.mlkit.vision.barcode.common.Barcode
+import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
+import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
+import com.togitech.ccp.component.TogiCountryCodePicker
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.mifospay.core.designsystem.component.MfOutlinedTextField
+import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel
+import org.mifospay.core.designsystem.component.MifosButton
+import org.mifospay.core.designsystem.component.MifosNavigationTopAppBar
+import org.mifospay.core.designsystem.theme.styleMedium16sp
+import org.mifospay.core.designsystem.theme.styleNormal18sp
+
+
+enum class SendMethodType {
+ VPA, MOBILE
+}
+
+@Composable
+fun SendScreenRoute(
+ viewModel: SendPaymentViewModel = hiltViewModel(),
+ showToolBar: Boolean,
+ onBackClick: () -> Unit,
+ proceedWithMakeTransferFlow: (String, String) -> Unit
+) {
+ val context = LocalContext.current
+ val selfVpa by viewModel.vpa.collectAsStateWithLifecycle()
+ val selfMobile by viewModel.mobile.collectAsStateWithLifecycle()
+ val showProgress by viewModel.showProgress.collectAsStateWithLifecycle()
+
+ fun showToast(message: String) {
+ Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
+ }
+
+ SendMoneyScreen(
+ showToolBar = showToolBar,
+ onBackClick = onBackClick,
+ showProgress = showProgress,
+ onSubmit = { amount, externalIdOrMobile, sendMethodType ->
+ if (!viewModel.checkSelfTransfer(
+ selfVpa = selfVpa,
+ selfMobile = selfMobile,
+ sendMethodType = sendMethodType,
+ externalIdOrMobile = externalIdOrMobile
+ )
+ ) {
+ viewModel.checkBalanceAvailabilityAndTransfer(
+ externalId = selfVpa,
+ transferAmount = amount.toDouble(),
+ onAnyError = {
+ showToast(context.getString(it))
+ },
+ proceedWithTransferFlow = { externalId, transferAmount ->
+ proceedWithMakeTransferFlow.invoke(externalIdOrMobile, transferAmount.toString())
+ }
+ )
+ } else {
+ showToast(context.getString(R.string.self_amount_transfer_is_not_allowed))
+ }
+ }
+ )
+}
+
+@Composable
+fun SendMoneyScreen(
+ showToolBar: Boolean,
+ showProgress: Boolean,
+ onSubmit: (String, String, SendMethodType) -> Unit,
+ onBackClick: () -> Unit,
+) {
+
+ val context = LocalContext.current
+
+ var amount by rememberSaveable { mutableStateOf("") }
+ var vpa by rememberSaveable { mutableStateOf("") }
+ var mobileNumber by rememberSaveable { mutableStateOf("") }
+ var isValidMobileNumber by rememberSaveable { mutableStateOf(false) }
+ var sendMethodType by rememberSaveable { mutableStateOf(SendMethodType.VPA) }
+ var isValidInfo by rememberSaveable { mutableStateOf(false) }
+
+ var contactUri by rememberSaveable { mutableStateOf(null) }
+
+ fun validateInfo() {
+ isValidInfo = when (sendMethodType) {
+ SendMethodType.VPA -> amount.isNotEmpty() && vpa.isNotEmpty()
+ SendMethodType.MOBILE -> {
+ isValidMobileNumber && mobileNumber.isNotEmpty() && amount.isNotEmpty()
+ }
+ }
+ }
+
+ val contactLauncher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.PickContact()
+ ) { uri: Uri? ->
+ uri?.let { contactUri = uri }
+ }
+
+ LaunchedEffect(key1 = contactUri) {
+ contactUri?.let {
+ mobileNumber = getContactPhoneNumber(it, context)
+ }
+ }
+
+ val permissionLauncher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.RequestPermission(),
+ onResult = { isGranted: Boolean ->
+ if (isGranted) {
+ contactLauncher.launch(null)
+ } else {
+ // Handle permission denial
+ }
+ }
+ )
+
+ val options = GmsBarcodeScannerOptions.Builder()
+ .setBarcodeFormats(
+ Barcode.FORMAT_QR_CODE,
+ Barcode.FORMAT_AZTEC
+ )
+ .build()
+
+ val scanner = GmsBarcodeScanning.getClient(context, options)
+
+ fun startScan() {
+ scanner.startScan()
+ .addOnSuccessListener { barcode ->
+ barcode.rawValue?.let {
+ vpa = it
+ }
+ }
+ .addOnCanceledListener {
+ // Task canceled
+ }
+ .addOnFailureListener { e ->
+ // Task failed with an exception
+ e.localizedMessage?.let { Log.d("SendMoney: Barcode scan failed", it) }
+ }
+ }
+
+ Box {
+ Column(Modifier.fillMaxSize()) {
+ if (showToolBar) {
+ MifosNavigationTopAppBar(
+ titleRes = R.string.send,
+ onNavigationClick = onBackClick
+ )
+ }
+ Text(
+ modifier = Modifier.padding(start = 20.dp, top = 20.dp),
+ text = stringResource(id = R.string.select_transfer_method),
+ style = styleNormal18sp
+ )
+ Column(modifier = Modifier.padding(16.dp)) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 20.dp, bottom = 20.dp)
+ ) {
+ VpaMobileChip(
+ selected = sendMethodType == SendMethodType.VPA,
+ onClick = { sendMethodType = SendMethodType.VPA },
+ label = stringResource(id = R.string.vpa)
+ )
+ Spacer(modifier = Modifier.width(8.dp))
+ VpaMobileChip(
+ selected = sendMethodType == SendMethodType.MOBILE,
+ onClick = { sendMethodType = SendMethodType.MOBILE },
+ label = stringResource(id = R.string.mobile)
+ )
+ }
+ MfOutlinedTextField(
+ value = amount,
+ onValueChange = {
+ amount = it
+ validateInfo()
+ },
+ singleLine = true,
+ keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
+ label = stringResource(id = R.string.amount),
+ modifier = Modifier.fillMaxWidth()
+ )
+ when (sendMethodType) {
+ SendMethodType.VPA -> {
+ MfOutlinedTextField(
+ value = vpa,
+ onValueChange = {
+ vpa = it
+ validateInfo()
+ },
+ label = stringResource(id = R.string.virtual_payment_address),
+ modifier = Modifier.fillMaxWidth(),
+ trailingIcon = {
+ IconButton(onClick = {
+ startScan()
+ }) {
+ Icon(
+ imageVector = Icons.Filled.QrCode2,
+ contentDescription = "Scan QR",
+ tint = Color.Blue
+ )
+ }
+ }
+ )
+ }
+
+ SendMethodType.MOBILE -> {
+ EnterPhoneScreen(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 8.dp),
+ initialPhoneNumber = mobileNumber,
+ onNumberUpdated = { _, fullPhone, valid ->
+ if (valid) {
+ mobileNumber = fullPhone
+ }
+ isValidMobileNumber = valid
+ validateInfo()
+ }
+ )
+ }
+ }
+ Spacer(modifier = Modifier.height(16.dp))
+ MifosButton(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ .align(Alignment.CenterHorizontally),
+ color = Color.Black,
+ enabled = isValidInfo,
+ onClick = {
+ if (!isValidInfo) return@MifosButton
+ onSubmit(
+ amount,
+ when (sendMethodType) {
+ SendMethodType.VPA -> vpa
+ SendMethodType.MOBILE -> mobileNumber
+ },
+ sendMethodType
+ )
+ //TODO: Navigate to MakeTransferScreenRoute
+ },
+ contentPadding = PaddingValues(12.dp)
+ ) {
+ Text(
+ stringResource(id = R.string.submit),
+ style = styleMedium16sp.copy(color = Color.White)
+ )
+ }
+ }
+ }
+ if (showProgress) {
+ MfOverlayLoadingWheel(
+ contentDesc = stringResource(id = R.string.please_wait)
+ )
+ }
+ }
+}
+
+@Composable
+fun EnterPhoneScreen(
+ modifier: Modifier,
+ initialPhoneNumber: String? = null,
+ onNumberUpdated: (String, String, Boolean) -> Unit
+) {
+ val keyboardController = LocalSoftwareKeyboardController.current
+ TogiCountryCodePicker(
+ modifier = modifier,
+ shape = RoundedCornerShape(8.dp),
+ colors = TextFieldDefaults.outlinedTextFieldColors(
+ focusedBorderColor = MaterialTheme.colorScheme.primary
+ ),
+ initialPhoneNumber = initialPhoneNumber,
+ onValueChange = { (code, phone), isValid ->
+ onNumberUpdated(phone, code + phone, isValid)
+ },
+ label = { Text(stringResource(id = R.string.phone_number)) },
+ keyboardActions = KeyboardActions { keyboardController?.hide() }
+ )
+}
+
+@Composable
+fun VpaMobileChip(selected: Boolean, onClick: () -> Unit, label: String) {
+ MifosButton(
+ onClick = onClick,
+ color = if (selected) Color.Black else Color.LightGray,
+ modifier = Modifier
+ .padding(4.dp)
+ .wrapContentSize()
+ ) {
+ Text(
+ modifier = Modifier.padding(top = 4.dp, bottom = 4.dp),
+ text = label,
+ )
+ }
+}
+
+suspend fun getContactPhoneNumber(uri: Uri, context: Context): String {
+ val contactId: String = uri.lastPathSegment ?: return ""
+ return withContext(Dispatchers.IO) {
+ val phoneCursor = context.contentResolver.query(
+ ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
+ arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER),
+ "${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} = ?",
+ arrayOf(contactId),
+ null
+ )
+ phoneCursor?.use { cursor ->
+ if (cursor.moveToFirst()) {
+ val phoneNumberIndex =
+ cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
+ cursor.getString(phoneNumberIndex)
+ } else {
+ ""
+ }
+ } ?: ""
+ }
+}
+
+
+@Preview(showSystemUi = true, showBackground = true)
+@Composable
+fun SendMoneyScreenWithToolBarPreview() {
+ SendMoneyScreen(
+ onSubmit = { _, _, _ -> },
+ onBackClick = {},
+ showProgress = false,
+ showToolBar = true
+ )
+}
+
+@Preview(showSystemUi = true, showBackground = true)
+@Composable
+fun SendMoneyScreenWithoutToolBarPreview() {
+ SendMoneyScreen(
+ onSubmit = { _, _, _ -> },
+ onBackClick = {},
+ showProgress = false,
+ showToolBar = false
+ )
+}
diff --git a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/navigation/SendNavigation.kt b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/navigation/SendNavigation.kt
new file mode 100644
index 000000000..49f0a0ad0
--- /dev/null
+++ b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/navigation/SendNavigation.kt
@@ -0,0 +1,26 @@
+package org.mifospay.feature.send.money.navigation
+
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.NavOptions
+import androidx.navigation.compose.composable
+import org.mifospay.feature.send.money.SendScreenRoute
+
+const val SEND_MONEY_ROUTE = "send_money_route"
+
+fun NavController.navigateToSendMoneyScreen(
+ navOptions: NavOptions? = null
+) = navigate(SEND_MONEY_ROUTE, navOptions)
+
+fun NavGraphBuilder.sendMoneyScreen(
+ proceedWithMakeTransferFlow: (String, String?) -> Unit,
+ onBackClick: () -> Unit
+) {
+ composable(route = SEND_MONEY_ROUTE) {
+ SendScreenRoute(
+ showToolBar = true,
+ onBackClick = onBackClick,
+ proceedWithMakeTransferFlow = proceedWithMakeTransferFlow
+ )
+ }
+}
diff --git a/feature/send-money/src/main/res/values/strings.xml b/feature/send-money/src/main/res/values/strings.xml
new file mode 100644
index 000000000..0a045245f
--- /dev/null
+++ b/feature/send-money/src/main/res/values/strings.xml
@@ -0,0 +1,14 @@
+
+ Insufficient balance
+ Error fetching balance
+ Self Account transfer is not allowed
+ Send
+ Select transfer method
+ VPA
+ Mobile number
+ Amount
+ Virtual Payment Address
+ Submit
+ Please wait…
+ Phone Number
+
\ No newline at end of file
diff --git a/feature/send-money/src/test/java/org/mifospay/feature/send/money/ExampleUnitTest.kt b/feature/send-money/src/test/java/org/mifospay/feature/send/money/ExampleUnitTest.kt
new file mode 100644
index 000000000..1d7ba503a
--- /dev/null
+++ b/feature/send-money/src/test/java/org/mifospay/feature/send/money/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package org.mifospay.feature.send.money
+
+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/mifospay/src/main/java/org/mifospay/common/ui/MakeTransferFragment.kt b/mifospay/src/main/java/org/mifospay/common/ui/MakeTransferFragment.kt
index ebd8198a9..1b43e8774 100644
--- a/mifospay/src/main/java/org/mifospay/common/ui/MakeTransferFragment.kt
+++ b/mifospay/src/main/java/org/mifospay/common/ui/MakeTransferFragment.kt
@@ -28,6 +28,7 @@ import javax.inject.Inject
/**
* Created by naman on 30/8/17.
+ * Moved to the feature/make-transfer
*/
@AndroidEntryPoint
class MakeTransferFragment : BottomSheetDialogFragment(), TransferContract.TransferView {
diff --git a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt b/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt
index ec3e87018..8576ab992 100644
--- a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt
+++ b/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt
@@ -74,7 +74,9 @@ fun MifosNavHost(
navController.navigateToMakeTransferScreen(externalId, transferAmount)
}
)
- makeTransferScreen()
+ makeTransferScreen(
+ onDismiss = navController::popBackStack
+ )
}
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 822ce0cba..94186a8da 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -36,3 +36,4 @@ include(":core:analytics")
include(":feature:passcode")
include(":feature:auth")
include(":feature:make-transfer")
+include(":feature:send-money")