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.background
import androidx.compose.foundation.clickable 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.layout.statusBarsPadding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons 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.Backspace
import androidx.compose.material.icons.rounded.KeyboardArrowLeft
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable 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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign 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.dp
import androidx.compose.ui.unit.sp 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 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 @Composable
fun NumericEntryScreen( fun NumericEntryScreen(
title: String, title: String,
@ -226,7 +173,7 @@ fun NumericEntryScreen(
elevation = CardDefaults.cardElevation(defaultElevation = 6.dp) elevation = CardDefaults.cardElevation(defaultElevation = 6.dp)
) { ) {
Icon( Icon(
imageVector = Icons.Rounded.Backspace, imageVector = Icons.AutoMirrored.Rounded.Backspace,
contentDescription = "Delete", contentDescription = "Delete",
tint = if (canDelete) Color.LegacyRed else Color.Gray, tint = if (canDelete) Color.LegacyRed else Color.Gray,
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp) 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 androidx.compose.runtime.Composable
import com.mob.utsmyanmar.model.ProcessCode import com.mob.utsmyanmar.model.ProcessCode
@ -12,7 +12,7 @@ fun AmountRoute(
onBack: () -> Unit, onBack: () -> Unit,
onNavigateCardWaiting: () -> Unit onNavigateCardWaiting: () -> Unit
) { ) {
AmountScreen( InputAmount(
title = action.ifBlank { "Amount" }, title = action.ifBlank { "Amount" },
onBackClick = onBack, onBackClick = onBack,
onChargeClick = { amount -> 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.compose.composable
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.mob.utsmyanmar.model.ProcessCode 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.CardWaitingScreen
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2 import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2

View File

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

View File

@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue 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.mob.utsmyanmar.viewmodel.SharedViewModel
import com.utsmyanmar.paylibs.utils.POSUtil import com.utsmyanmar.paylibs.utils.POSUtil