Skip to content

Commit daa3a5f

Browse files
committed
feat(feature:send-money): add basic structure for pay anyone screen
1 parent 278e1aa commit daa3a5f

File tree

3 files changed

+236
-1
lines changed

3 files changed

+236
-1
lines changed

cmp-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ import org.mifospay.feature.savedcards.details.navigateToCardDetails
7373
import org.mifospay.feature.send.money.SendMoneyScreen
7474
import org.mifospay.feature.send.money.navigation.SEND_MONEY_BASE_ROUTE
7575
import org.mifospay.feature.send.money.navigation.SEND_MONEY_OPTIONS_ROUTE
76+
import org.mifospay.feature.send.money.navigation.navigateToPayAnyoneScreen
7677
import org.mifospay.feature.send.money.navigation.navigateToPayeeDetailsScreen
7778
import org.mifospay.feature.send.money.navigation.navigateToSendMoneyOptionsScreen
7879
import org.mifospay.feature.send.money.navigation.navigateToSendMoneyScreen
80+
import org.mifospay.feature.send.money.navigation.payAnyoneScreen
7981
import org.mifospay.feature.send.money.navigation.payeeDetailsScreen
8082
import org.mifospay.feature.send.money.navigation.sendMoneyOptionsScreen
8183
import org.mifospay.feature.send.money.navigation.sendMoneyScreen
@@ -291,7 +293,7 @@ internal fun MifosNavHost(
291293
// This is now handled by the ViewModel using ML Kit scanner
292294
},
293295
onPayAnyoneClick = {
294-
// TODO: Navigate to Pay Anyone screen
296+
navController.navigateToPayAnyoneScreen()
295297
},
296298
onBankTransferClick = {
297299
// TODO: Navigate to Bank Transfer screen
@@ -321,6 +323,10 @@ internal fun MifosNavHost(
321323
navigateToScanQrScreen = navController::navigateToScanQr,
322324
)
323325

326+
payAnyoneScreen(
327+
onBackClick = navController::popBackStack,
328+
)
329+
324330
payeeDetailsScreen(
325331
onBackClick = navController::popBackStack,
326332
onNavigateToUpiPayment = { state ->
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright 2024 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md
9+
*/
10+
package org.mifospay.feature.send.money
11+
12+
import androidx.compose.animation.AnimatedContent
13+
import androidx.compose.animation.core.tween
14+
import androidx.compose.animation.fadeIn
15+
import androidx.compose.animation.fadeOut
16+
import androidx.compose.animation.slideInVertically
17+
import androidx.compose.animation.slideOutVertically
18+
import androidx.compose.animation.togetherWith
19+
import androidx.compose.foundation.layout.Column
20+
import androidx.compose.foundation.layout.Row
21+
import androidx.compose.foundation.layout.Spacer
22+
import androidx.compose.foundation.layout.fillMaxWidth
23+
import androidx.compose.foundation.layout.height
24+
import androidx.compose.foundation.layout.padding
25+
import androidx.compose.foundation.layout.size
26+
import androidx.compose.foundation.layout.width
27+
import androidx.compose.foundation.text.KeyboardOptions
28+
import androidx.compose.material3.Icon
29+
import androidx.compose.material3.IconButton
30+
import androidx.compose.material3.IconButtonDefaults
31+
import androidx.compose.material3.Text
32+
import androidx.compose.runtime.Composable
33+
import androidx.compose.runtime.LaunchedEffect
34+
import androidx.compose.runtime.getValue
35+
import androidx.compose.runtime.mutableStateOf
36+
import androidx.compose.runtime.remember
37+
import androidx.compose.runtime.setValue
38+
import androidx.compose.ui.Alignment
39+
import androidx.compose.ui.Modifier
40+
import androidx.compose.ui.text.input.KeyboardType
41+
import androidx.compose.ui.text.style.TextAlign
42+
import androidx.compose.ui.unit.dp
43+
import kotlinx.coroutines.delay
44+
import org.mifospay.core.designsystem.component.MifosGradientBackground
45+
import org.mifospay.core.designsystem.component.MifosOutlinedTextField
46+
import org.mifospay.core.designsystem.component.MifosScaffold
47+
import org.mifospay.core.designsystem.component.MifosTopBar
48+
import org.mifospay.core.designsystem.icon.MifosIcons
49+
import template.core.base.designsystem.theme.KptTheme
50+
51+
@Composable
52+
fun PayAnyoneScreen(
53+
onBackClick: () -> Unit,
54+
modifier: Modifier = Modifier,
55+
) {
56+
var inputValue by remember { mutableStateOf("") }
57+
var isKeyboardNumeric by remember { mutableStateOf(false) }
58+
var showClearIcon by remember { mutableStateOf(false) }
59+
var currentPlaceholderIndex by remember { mutableStateOf(0) }
60+
61+
val placeholderMessages = listOf(
62+
"Enter UPI ID or number",
63+
"Enter phone number or name",
64+
)
65+
66+
val currentPlaceholder = placeholderMessages[currentPlaceholderIndex]
67+
68+
val keyboardType = if (isKeyboardNumeric) {
69+
KeyboardType.Number
70+
} else {
71+
KeyboardType.Text
72+
}
73+
74+
val keyboardToggleText = if (isKeyboardNumeric) "ABC" else "123"
75+
76+
LaunchedEffect(Unit) {
77+
while (true) {
78+
delay(3000)
79+
currentPlaceholderIndex = (currentPlaceholderIndex + 1) % placeholderMessages.size
80+
}
81+
}
82+
83+
MifosGradientBackground {
84+
MifosScaffold(
85+
modifier = modifier,
86+
topBar = {
87+
MifosTopBar(
88+
topBarTitle = "Pay Anyone",
89+
backPress = onBackClick,
90+
)
91+
},
92+
) { paddingValues ->
93+
Column(
94+
modifier = Modifier
95+
.fillMaxWidth()
96+
.padding(paddingValues)
97+
.padding(horizontal = KptTheme.spacing.lg),
98+
) {
99+
Spacer(modifier = Modifier.height(KptTheme.spacing.md))
100+
101+
Text(
102+
text = "Pay any UPI app using name, number or UPI ID",
103+
style = KptTheme.typography.titleSmall,
104+
textAlign = TextAlign.Start,
105+
modifier = Modifier.fillMaxWidth(),
106+
)
107+
108+
Spacer(modifier = Modifier.height(KptTheme.spacing.lg))
109+
110+
MifosOutlinedTextField(
111+
value = inputValue,
112+
onValueChange = {
113+
inputValue = it
114+
showClearIcon = it.isNotEmpty()
115+
},
116+
label = "",
117+
placeholder = null,
118+
leadingIcon = {
119+
AnimatedContent(
120+
targetState = currentPlaceholder,
121+
transitionSpec = {
122+
slideInVertically(
123+
animationSpec = tween(500),
124+
initialOffsetY = { fullHeight -> fullHeight },
125+
) + fadeIn(animationSpec = tween(500)) togetherWith
126+
slideOutVertically(
127+
animationSpec = tween(500),
128+
targetOffsetY = { fullHeight -> -fullHeight },
129+
) + fadeOut(animationSpec = tween(500))
130+
},
131+
) { placeholder ->
132+
Text(
133+
text = placeholder,
134+
style = KptTheme.typography.bodyMedium,
135+
color = KptTheme.colorScheme.onSurface.copy(alpha = 0.6f),
136+
modifier = Modifier.padding(start = KptTheme.spacing.sm),
137+
)
138+
}
139+
},
140+
keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
141+
trailingIcon = {
142+
Row(
143+
verticalAlignment = Alignment.CenterVertically,
144+
) {
145+
AnimatedContent(
146+
targetState = showClearIcon,
147+
transitionSpec = {
148+
fadeIn(animationSpec = tween(200)) togetherWith
149+
fadeOut(animationSpec = tween(200))
150+
},
151+
) { showClear ->
152+
if (showClear) {
153+
IconButton(
154+
onClick = {
155+
inputValue = ""
156+
showClearIcon = false
157+
},
158+
colors = IconButtonDefaults.iconButtonColors(
159+
contentColor = KptTheme.colorScheme.onSurface.copy(alpha = 0.6f),
160+
),
161+
) {
162+
Icon(
163+
imageVector = MifosIcons.Close,
164+
contentDescription = "Clear input",
165+
modifier = Modifier.size(20.dp),
166+
)
167+
}
168+
} else {
169+
Row {
170+
IconButton(
171+
onClick = {
172+
isKeyboardNumeric = !isKeyboardNumeric
173+
},
174+
colors = IconButtonDefaults.iconButtonColors(
175+
contentColor = KptTheme.colorScheme.primary,
176+
),
177+
) {
178+
Text(
179+
text = keyboardToggleText,
180+
style = KptTheme.typography.labelMedium,
181+
color = KptTheme.colorScheme.primary,
182+
)
183+
}
184+
185+
Spacer(modifier = Modifier.width(KptTheme.spacing.xs))
186+
187+
IconButton(
188+
onClick = {
189+
// TODO: Implement contact picker functionality
190+
},
191+
colors = IconButtonDefaults.iconButtonColors(
192+
contentColor = KptTheme.colorScheme.primary,
193+
),
194+
) {
195+
Icon(
196+
imageVector = MifosIcons.Contact,
197+
contentDescription = "Select from contacts",
198+
modifier = Modifier.size(20.dp),
199+
)
200+
}
201+
}
202+
}
203+
}
204+
}
205+
},
206+
)
207+
}
208+
}
209+
}
210+
}

feature/send-money/src/commonMain/kotlin/org/mifospay/feature/send/money/navigation/SendNavigation.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import androidx.navigation.NavType
1616
import androidx.navigation.navArgument
1717
import androidx.navigation.navOptions
1818
import org.mifospay.core.ui.composableWithSlideTransitions
19+
import org.mifospay.feature.send.money.PayAnyoneScreen
1920
import org.mifospay.feature.send.money.PayeeDetailsScreen
2021
import org.mifospay.feature.send.money.PayeeDetailsState
2122
import org.mifospay.feature.send.money.SendMoneyOptionsScreen
@@ -32,6 +33,12 @@ const val PAYEE_DETAILS_ARG = "qrCodeData"
3233

3334
const val PAYEE_DETAILS_BASE_ROUTE = "$PAYEE_DETAILS_ROUTE?$PAYEE_DETAILS_ARG={$PAYEE_DETAILS_ARG}"
3435

36+
const val PAY_ANYONE_ROUTE = "pay_anyone_route"
37+
38+
fun NavController.navigateToPayAnyoneScreen(
39+
navOptions: NavOptions? = null,
40+
) = navigate(PAY_ANYONE_ROUTE, navOptions)
41+
3542
fun NavController.navigateToSendMoneyScreen(
3643
navOptions: NavOptions? = null,
3744
) = navigate(SEND_MONEY_ROUTE, navOptions)
@@ -101,6 +108,18 @@ fun NavGraphBuilder.sendMoneyOptionsScreen(
101108
}
102109
}
103110

111+
fun NavGraphBuilder.payAnyoneScreen(
112+
onBackClick: () -> Unit,
113+
) {
114+
composableWithSlideTransitions(
115+
route = PAY_ANYONE_ROUTE,
116+
) {
117+
PayAnyoneScreen(
118+
onBackClick = onBackClick,
119+
)
120+
}
121+
}
122+
104123
fun NavGraphBuilder.payeeDetailsScreen(
105124
onBackClick: () -> Unit,
106125
onNavigateToUpiPayment: (PayeeDetailsState) -> Unit,

0 commit comments

Comments
 (0)