input amount screen responsive screen size

This commit is contained in:
moon 2026-05-28 15:17:57 +06:30
parent 4aebd825d2
commit f95208aa9d
6 changed files with 324 additions and 137 deletions

View File

@ -1,4 +1,4 @@
package com.mob.utsmyanmar.ui.amount
package com.mob.utsmyanmar.ui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -15,77 +15,24 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.automirrored.rounded.Backspace
import androidx.compose.material.icons.rounded.Backspace
import androidx.compose.material.icons.rounded.KeyboardArrowLeft
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.preview.P2Preview
import com.mob.utsmyanmar.ui.preview.P3Preview
import com.mob.utsmyanmar.ui.theme.Color
@Composable
fun AmountScreen(
title: String = "Amount",
onBackClick: () -> Unit = {},
onChargeClick: (String) -> Unit = {}
) {
var amount by remember { mutableStateOf("") }
Scaffold(
topBar = {
AppBar(title = title, icon = Icons.Default.ArrowBackIosNew, onIconClick = onBackClick)
}
) { paddingValues ->
NumericEntryScreen(
modifier = Modifier.padding(paddingValues),
title = title,
prompt = "Enter $title",
displayValue = formatAmount(amount.ifEmpty { "0" }),
supportingText = "Enter the amount to continue",
confirmText = "Next",
prefixLabel = "MMK",
onBackClick = onBackClick,
onCancelClick = onBackClick,
onConfirmClick = {
if (amount.isNotEmpty()) {
onChargeClick(amount)
}
},
onKeyClick = { value ->
amount = appendAmountValue(amount, value)
},
onDeleteClick = {
amount = amount.dropLast(1)
},
confirmEnabled = amount.isNotEmpty(),
canDelete = amount.isNotEmpty()
)
}
}
@Composable
fun NumericEntryScreen(
title: String,
@ -226,7 +173,7 @@ fun NumericEntryScreen(
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)
) {
Icon(
imageVector = Icons.Rounded.Backspace,
imageVector = Icons.AutoMirrored.Rounded.Backspace,
contentDescription = "Delete",
tint = if (canDelete) Color.LegacyRed else Color.Gray,
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp)
@ -293,78 +240,3 @@ private fun KeypadButton(
)
}
}
private fun formatAmount(value: String): String {
val normalized = value.ifEmpty { "0" }
val wholePart = normalized.substringBefore(".").ifEmpty { "0" }
val groupedWholePart = "%,d".format(wholePart.toLongOrNull() ?: 0L)
if (!normalized.contains(".")) {
return groupedWholePart
}
val decimalPart = normalized.substringAfter(".", "")
return if (normalized.endsWith(".")) {
"$groupedWholePart."
} else {
"$groupedWholePart.$decimalPart"
}
}
private fun appendAmountValue(current: String, value: String): String {
if (value == ".") {
if (current.contains(".")) return current
return if (current.isEmpty()) "0." else "$current."
}
val decimalIndex = current.indexOf('.')
return if (decimalIndex >= 0) {
val decimalPart = current.substring(decimalIndex + 1)
val remainingDecimalDigits = 2 - decimalPart.length
if (remainingDecimalDigits <= 0) {
current
} else {
current + value.take(remainingDecimalDigits)
}
} else {
val wholeDigitsCount = current.filter(Char::isDigit).length
val remainingWholeDigits = 9 - wholeDigitsCount
if (remainingWholeDigits <= 0) {
current
} else {
current + value.take(remainingWholeDigits)
}
}
}
@P2Preview
@Composable
fun PreviewAmountScreen2() {
AmountScreen { }
}
@P3Preview
@Composable
fun PreviewAmountScreen3() {
AmountScreen { }
}
@Preview(showBackground = true)
@Composable
private fun PreviewNumericEntryScreen() {
NumericEntryScreen(
title = "Amount",
prompt = "Enter Amount",
displayValue = "12,500",
supportingText = "Enter the amount to continue",
confirmText = "Next",
onBackClick = {},
onCancelClick = {},
onConfirmClick = {},
onKeyClick = {},
onDeleteClick = {},
prefixLabel = "MMK",
confirmEnabled = true,
canDelete = true
)
}

View File

@ -1,4 +1,4 @@
package com.mob.utsmyanmar.ui.amount
package com.mob.utsmyanmar.ui.input_amount
import androidx.compose.runtime.Composable
import com.mob.utsmyanmar.model.ProcessCode
@ -12,7 +12,7 @@ fun AmountRoute(
onBack: () -> Unit,
onNavigateCardWaiting: () -> Unit
) {
AmountScreen(
InputAmount(
title = action.ifBlank { "Amount" },
onBackClick = onBack,
onChargeClick = { amount ->

View File

@ -0,0 +1,315 @@
package com.mob.utsmyanmar.ui.input_amount
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.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.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.Backspace
import androidx.compose.material.icons.rounded.Backspace
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.preview.P2Preview
import com.mob.utsmyanmar.ui.preview.P3Preview
import com.mob.utsmyanmar.ui.theme.Color
import kotlin.collections.List
@Composable
fun InputAmount(
title: String = "Amount",
onBackClick: () -> Unit = {},
onChargeClick: (String) -> Unit = {}
){
var amount by remember { mutableStateOf("") }
val prefixLabel = "MMK"
val supportingText = "Enter the amount to continue"
Scaffold(
topBar = { AppBar(title = "Amount") },
containerColor = Color.IvoryBeige
) {paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize()
.padding(16.dp)
) {
Spacer(Modifier.height(8.dp))
//first container
Box(
modifier = Modifier
.fillMaxSize()
.weight(1f),
){
Card(
modifier = Modifier.align(Alignment.CenterEnd)
.clickable(enabled = true) {
amount = amount.dropLast(1)
},
shape = RoundedCornerShape(18.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)
) {
Icon(
imageVector = Icons.Rounded.Backspace,
contentDescription = "Delete",
tint = Color.LegacyRed,
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp)
)
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Enter Amount",
color = Color.Gray,
fontSize = 11.sp,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier.align(Alignment.CenterHorizontally),
verticalAlignment = Alignment.Bottom
) {
if (prefixLabel.isNotBlank()) {
Text(
text = prefixLabel,
color = Color.LegacyRed,
fontSize = 13.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.padding(end = 10.dp, bottom = 6.dp)
)
}
Text(
text = formatAmount(amount.ifEmpty { "0" }),
color = Color.LegacyRed,
fontSize = 32.sp,
fontWeight = FontWeight.Bold
)
}
Spacer(modifier = Modifier.height(12.dp))
Text(
text = supportingText,
color = Color.Gray,
fontSize = 11.sp,
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
}
//second container
Column(
modifier = Modifier
.fillMaxWidth()
.weight(3f),
verticalArrangement = Arrangement.Bottom
){
NumericKeypad(
onKeyClick = { value ->
amount = appendAmountValue(amount, value)
}
)
}
Spacer(Modifier.height(16.dp))
//third container
Box(
modifier = Modifier
.fillMaxWidth()
.weight(0.5f)
){
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
Button(
onClick = {},
modifier = Modifier
.weight(1f)
.height(56.dp),
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color.White,
contentColor = Color.LegacyRed
)
) {
Text("Cancel")
}
Button(
onClick = {
if (amount.isNotEmpty()) {
onChargeClick(amount)
} },
modifier = Modifier
.weight(1f)
.height(56.dp),
enabled = amount.isNotEmpty(),
shape = RoundedCornerShape(8.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color.LegacyRed,
contentColor = Color.White,
disabledContainerColor = Color.LegacyRed.copy(alpha = 0.5f),
disabledContentColor = Color.White
)
) {
Text(
text = "Next",
fontSize = 14.sp,
fontWeight = FontWeight.Medium
)
}
}
}
}
}
}
@Composable
private fun NumericKeypad(
onKeyClick: (String) -> Unit
) {
val keys : List<List<String>> = listOf(
listOf("1", "2", "3"),
listOf("4", "5", "6"),
listOf("7", "8", "9"),
listOf(".", "0", "00")
)
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(6.dp)
) {
keys.forEach { row ->
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
row.forEach { key ->
KeypadButton(
text = key,
modifier = Modifier.weight(1f),
onClick = { onKeyClick(key) }
)
}
}
}
}
}
@Composable
private fun KeypadButton(
text: String,
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
val enabled = text.isNotBlank()
Box(
modifier = modifier
.height(66.dp)
.shadow(
elevation = 2.dp,
shape = RoundedCornerShape(8.dp),
clip = false
)
.background(
color = Color.White,
shape = RoundedCornerShape(8.dp)
)
.clickable(enabled = enabled) { onClick() },
contentAlignment = Alignment.Center
) {
Text(
text = text,
color = if (enabled) Color.LegacyRed else Color.White,
fontSize = 24.sp,
fontWeight = FontWeight.Normal,
textAlign = TextAlign.Center
)
}
}
private fun appendAmountValue(current: String, value: String): String {
if (value == ".") {
if (current.contains(".")) return current
return if (current.isEmpty()) "0." else "$current."
}
val decimalIndex = current.indexOf('.')
return if (decimalIndex >= 0) {
val decimalPart = current.substring(decimalIndex + 1)
val remainingDecimalDigits = 2 - decimalPart.length
if (remainingDecimalDigits <= 0) {
current
} else {
current + value.take(remainingDecimalDigits)
}
} else {
val wholeDigitsCount = current.filter(Char::isDigit).length
val remainingWholeDigits = 9 - wholeDigitsCount
if (remainingWholeDigits <= 0) {
current
} else {
current + value.take(remainingWholeDigits)
}
}
}
private fun formatAmount(value: String): String {
val normalized = value.ifEmpty { "0" }
val wholePart = normalized.substringBefore(".").ifEmpty { "0" }
val groupedWholePart = "%,d".format(wholePart.toLongOrNull() ?: 0L)
if (!normalized.contains(".")) {
return groupedWholePart
}
val decimalPart = normalized.substringAfter(".", "")
return if (normalized.endsWith(".")) {
"$groupedWholePart."
} else {
"$groupedWholePart.$decimalPart"
}
}
@P2Preview
@P3Preview
@Composable
fun PreviewInputAmount(){
InputAmount();
}

View File

@ -12,7 +12,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.mob.utsmyanmar.model.ProcessCode
import com.mob.utsmyanmar.ui.amount.AmountRoute
import com.mob.utsmyanmar.ui.input_amount.AmountRoute
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2

View File

@ -5,7 +5,7 @@ import androidx.compose.ui.tooling.preview.Preview
@Preview(
name = "P2",
device = "spec:width=720px,height=1440px,dpi=349",
device = "spec:width=720px,height=1440px,dpi=350",
showBackground = true,
showSystemUi = true
)
@ -13,7 +13,7 @@ annotation class P2Preview
@Preview(
name = "P3",
device = "spec:width=720px,height=1600px,dpi=320",
device = "spec:width=720px,height=1600px,dpi=300",
showBackground = true,
showSystemUi = true
)

View File

@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import com.mob.utsmyanmar.ui.amount.NumericEntryScreen
import com.mob.utsmyanmar.ui.components.NumericEntryScreen
import com.mob.utsmyanmar.viewmodel.SharedViewModel
import com.utsmyanmar.paylibs.utils.POSUtil