From 582b08ceadf204d823bc8c3ccdd4a99dd6ea9026 Mon Sep 17 00:00:00 2001 From: moon <56061215+MgKyawLay@users.noreply.github.com> Date: Wed, 10 Jun 2026 21:46:17 +0630 Subject: [PATCH] responsive keypad --- .../ui/components/NumericEntryScreen.kt | 62 ---- .../utsmyanmar/ui/components/NumericKeypad.kt | 104 ++++++ .../ui/input_amount/InputAmountScreen.kt | 78 +---- .../ui/password_input/PasswordInput.kt | 313 +++++++----------- 4 files changed, 232 insertions(+), 325 deletions(-) create mode 100644 app/src/main/java/com/mob/utsmyanmar/ui/components/NumericKeypad.kt diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericEntryScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericEntryScreen.kt index 93e310d..5fc4ee0 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericEntryScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericEntryScreen.kt @@ -16,7 +16,6 @@ import androidx.compose.foundation.layout.statusBarsPadding 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 @@ -26,9 +25,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable 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.theme.Color @@ -181,62 +178,3 @@ fun NumericEntryScreen( } } } - -@Composable -private fun NumericKeypad( - keys: List>, - onKeyClick: (String) -> Unit -) { - 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 - ) - } -} diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericKeypad.kt b/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericKeypad.kt new file mode 100644 index 0000000..bc1e990 --- /dev/null +++ b/app/src/main/java/com/mob/utsmyanmar/ui/components/NumericKeypad.kt @@ -0,0 +1,104 @@ +package com.mob.utsmyanmar.ui.components + +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.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color as ComposeColor +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.theme.Color + +@Composable +fun NumericKeypad( + modifier: Modifier = Modifier, + onKeyClick: (String) -> Unit, + keys : List>, +) { +// val keys : List> = listOf( +// listOf("1", "2", "3"), +// listOf("4", "5", "6"), +// listOf("7", "8", "9"), +// listOf(".", "0", "00") +// ) + Column( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(6.dp) + ) { + keys.forEach { row -> + Row( + modifier = Modifier.fillMaxWidth().weight(1f), + horizontalArrangement = Arrangement.spacedBy(6.dp) + ) { + row.forEach { key -> + KeypadButton( + text = key, + modifier = Modifier.weight(1f).fillMaxHeight(), + onClick = { onKeyClick(key) } + ) + } + } + } + } +} + +@Composable +fun KeypadButton( + text: String, + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + val enabled = text.isNotBlank() + + Box( + modifier = modifier + .then( + if (enabled) Modifier.shadow(elevation = 2.dp, shape = RoundedCornerShape(8.dp), clip = false) + else Modifier + ) + .background( + color = if (enabled) Color.White else ComposeColor.Transparent, + shape = RoundedCornerShape(8.dp) + ) + .clickable(enabled = enabled) { onClick() }, + contentAlignment = Alignment.Center + ) { + if (enabled) { + Text( + text = text, + color = Color.LegacyRed, + fontSize = 24.sp, + fontWeight = FontWeight.Normal, + textAlign = TextAlign.Center + ) + } + } +} + +@Preview +@Composable +fun PreviewNumericKeypad(){ + val keys : List> = listOf( + listOf("1", "2", "3"), + listOf("4", "5", "6"), + listOf("7", "8", "9"), + listOf(".", "0", "00") + ) + NumericKeypad( + keys = keys, + onKeyClick = {} + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/input_amount/InputAmountScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/input_amount/InputAmountScreen.kt index 84d7b87..66b6b93 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/input_amount/InputAmountScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/input_amount/InputAmountScreen.kt @@ -1,20 +1,17 @@ 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.fillMaxHeight 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 @@ -30,16 +27,21 @@ 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.NumericKeypad 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 + +private val amountKeys = listOf( + listOf("1", "2", "3"), + listOf("4", "5", "6"), + listOf("7", "8", "9"), + listOf(".", "0", "00") +) @Composable fun InputAmount( @@ -140,6 +142,7 @@ fun InputAmount( verticalArrangement = Arrangement.Bottom ){ NumericKeypad( + keys = amountKeys, modifier = Modifier.fillMaxSize(), onKeyClick = { value -> amount = appendAmountValue(amount, value) @@ -202,69 +205,6 @@ fun InputAmount( } } -@Composable -private fun NumericKeypad( - modifier: Modifier = Modifier, - onKeyClick: (String) -> Unit -) { - val keys : List> = listOf( - listOf("1", "2", "3"), - listOf("4", "5", "6"), - listOf("7", "8", "9"), - listOf(".", "0", "00") - ) - Column( - modifier = modifier, - verticalArrangement = Arrangement.spacedBy(6.dp) - ) { - keys.forEach { row -> - Row( - modifier = Modifier.fillMaxWidth().weight(1f), - horizontalArrangement = Arrangement.spacedBy(6.dp) - ) { - row.forEach { key -> - KeypadButton( - text = key, - modifier = Modifier.weight(1f).fillMaxHeight(), - onClick = { onKeyClick(key) } - ) - } - } - } - } -} - -@Composable -private fun KeypadButton( - text: String, - modifier: Modifier = Modifier, - onClick: () -> Unit -) { - val enabled = text.isNotBlank() - - Box( - modifier = modifier - .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 == ".") { diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/password_input/PasswordInput.kt b/app/src/main/java/com/mob/utsmyanmar/ui/password_input/PasswordInput.kt index acf48ed..5cc027e 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/password_input/PasswordInput.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/password_input/PasswordInput.kt @@ -10,10 +10,8 @@ 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.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -33,30 +31,36 @@ 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.NumericKeypad 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 object PasswordType { - const val SYSTEM = "system_password" + const val SYSTEM = "system_password" const val SETTLEMENT = "settlement_password" - const val SETTING = "setting_password" + const val SETTING = "setting_password" } private val passwords = mapOf( PasswordType.SYSTEM to "111111", PasswordType.SETTING to "222222", - PasswordType.SETTLEMENT to "123456", + PasswordType.SETTLEMENT to "123456" ) private const val PASSWORD_LENGTH = 6 +private val passwordKeys = listOf( + listOf("1", "2", "3"), + listOf("4", "5", "6"), + listOf("7", "8", "9"), + listOf("", "0", "") +) + @Composable fun InputPassword( passwordType: String, @@ -73,154 +77,132 @@ fun InputPassword( }, containerColor = Color.IvoryBeige ) { paddingValues -> - PasswordEntryScreen( - modifier = Modifier.padding(paddingValues), - input = input, - errorMessage = errorMessage, - onBack = onBack, - onConfirm = { - if (input == expectedPassword) { - onPasswordCorrect() - } else { - errorMessage = "Incorrect password" - input = "" - } - }, - onKey = { digit -> - if (input.length < PASSWORD_LENGTH) { - input += digit - errorMessage = null - } - }, - onDelete = { - input = input.dropLast(1) - errorMessage = null - } - ) - } -} - -@Composable -private fun PasswordEntryScreen( - input: String, - errorMessage: String?, - onBack: () -> Unit, - onConfirm: () -> Unit, - onKey: (String) -> Unit, - onDelete: () -> Unit, - modifier: Modifier = Modifier -) { - val keys = listOf( - listOf("1", "2", "3"), - listOf("4", "5", "6"), - listOf("7", "8", "9"), - listOf("", "0", "") - ) - - Box( - modifier = modifier - .fillMaxSize() - .background(Color.White) - .navigationBarsPadding() - .statusBarsPadding() - ) { Column( modifier = Modifier + .padding(paddingValues) .fillMaxSize() - .padding(horizontal = 20.dp) + .padding(16.dp) ) { - Text( - text = "Enter Password", - color = Color.Gray, - fontSize = 11.sp, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) + Spacer(Modifier.height(8.dp)) - Spacer(modifier = Modifier.height(16.dp)) - - PasswordDots( - filledCount = input.length, - totalCount = PASSWORD_LENGTH, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - - Spacer(modifier = Modifier.height(12.dp)) - - Text( - text = errorMessage ?: "", - color = Color.LegacyRed, - fontSize = 11.sp, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - - Spacer(modifier = Modifier.height(24.dp)) - - NumericKeypad(keys = keys, onKeyClick = onKey) - - Spacer(modifier = Modifier.weight(1f)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp) + Box( + modifier = Modifier + .fillMaxSize() + .weight(2f) ) { - Button( - onClick = onBack, - modifier = Modifier.weight(1f).height(56.dp), - shape = RoundedCornerShape(8.dp), - colors = ButtonDefaults.buttonColors( - containerColor = Color.White, - contentColor = Color.LegacyRed - ) + Card( + modifier = Modifier + .align(Alignment.CenterEnd) + .clickable(enabled = input.isNotEmpty()) { + input = input.dropLast(1) + errorMessage = null + }, + shape = RoundedCornerShape(18.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 6.dp) ) { - Text("Cancel") + Icon( + imageVector = Icons.Rounded.Backspace, + contentDescription = "Delete", + tint = if (input.isNotEmpty()) Color.LegacyRed else Color.Gray, + modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp) + ) } - Button( - onClick = onConfirm, - modifier = Modifier.weight(1f).height(56.dp), - enabled = input.length == PASSWORD_LENGTH, - shape = RoundedCornerShape(8.dp), - colors = ButtonDefaults.buttonColors( - containerColor = Color.LegacyRed, - contentColor = Color.White, - disabledContainerColor = Color.LegacyRed.copy(alpha = 0.5f), - disabledContentColor = Color.White - ) + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally ) { - Text(text = "Next", fontSize = 14.sp, fontWeight = FontWeight.Medium) + Text( + text = "Enter Password", + color = Color.Gray, + fontSize = 18.sp + ) + Spacer(Modifier.height(16.dp)) + PasswordDots(filledCount = input.length, totalCount = PASSWORD_LENGTH) + Spacer(Modifier.height(8.dp)) + Text( + text = errorMessage ?: "", + color = Color.LegacyRed, + fontSize = 14.sp + ) } } - Spacer(modifier = Modifier.height(18.dp)) - } + // Keypad — mirrors InputAmountScreen weight(3f) section + Column( + modifier = Modifier + .fillMaxWidth() + .weight(3f), + verticalArrangement = Arrangement.Bottom + ) { + NumericKeypad( + keys = passwordKeys, + modifier = Modifier.fillMaxSize(), + onKeyClick = { digit -> + if (input.length < PASSWORD_LENGTH) { + input += digit + errorMessage = null + } + } + ) + } - Card( - modifier = Modifier - .align(Alignment.TopEnd) - .padding(top = 32.dp, end = 20.dp) - .clickable(enabled = input.isNotEmpty()) { onDelete() }, - shape = RoundedCornerShape(18.dp), - colors = CardDefaults.cardColors(containerColor = Color.White), - elevation = CardDefaults.cardElevation(defaultElevation = 6.dp) - ) { - Icon( - imageVector = Icons.Rounded.Backspace, - contentDescription = "Delete", - tint = if (input.isNotEmpty()) Color.LegacyRed else Color.Gray, - modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp) - ) + Spacer(Modifier.height(16.dp)) + + // Action buttons — mirrors InputAmountScreen weight(0.5f) section + Box( + modifier = Modifier + .fillMaxWidth() + .weight(0.5f) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Button( + onClick = onBack, + 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 (input == expectedPassword) { + onPasswordCorrect() + } else { + errorMessage = "Incorrect password" + input = "" + } + }, + modifier = Modifier.weight(1f).height(56.dp), + enabled = input.length == PASSWORD_LENGTH, + 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 PasswordDots( - filledCount: Int, - totalCount: Int, - modifier: Modifier = Modifier -) { +private fun PasswordDots(filledCount: Int, totalCount: Int) { Row( - modifier = modifier, horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.CenterVertically ) { @@ -229,7 +211,8 @@ private fun PasswordDots( modifier = Modifier .size(14.dp) .background( - color = if (index < filledCount) Color.LegacyRed else Color.Gray.copy(alpha = 0.3f), + color = if (index < filledCount) Color.LegacyRed + else Color.Gray.copy(alpha = 0.3f), shape = CircleShape ) ) @@ -237,64 +220,6 @@ private fun PasswordDots( } } -@Composable -private fun NumericKeypad( - keys: List>, - onKeyClick: (String) -> Unit -) { - 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) - .then( - if (enabled) Modifier.shadow(elevation = 2.dp, shape = RoundedCornerShape(8.dp), clip = false) - else Modifier - ) - .background( - color = if (enabled) Color.White else androidx.compose.ui.graphics.Color.Transparent, - shape = RoundedCornerShape(8.dp) - ) - .clickable(enabled = enabled) { onClick() }, - contentAlignment = Alignment.Center - ) { - Text( - text = text, - color = if (enabled) Color.LegacyRed else androidx.compose.ui.graphics.Color.Transparent, - fontSize = 24.sp, - fontWeight = FontWeight.Normal, - textAlign = TextAlign.Center - ) - } -} - @P3Preview @P2Preview @Composable