From dbc5424aabcc5b4fc8011c792f6101451e0c913d Mon Sep 17 00:00:00 2001 From: moon <56061215+MgKyawLay@users.noreply.github.com> Date: Thu, 21 May 2026 23:31:05 +0630 Subject: [PATCH] void screen and pinpad fix --- .gitignore | 2 + app/build.gradle.kts | 1 + .../mob/utsmyanmar/ui/amount/AmountRoute.kt | 66 +++- .../mob/utsmyanmar/ui/amount/AmountScreen.kt | 7 +- .../ui/cardwaiting/CardWaitingScreen.kt | 2 +- .../ui/dashboard/DashboardScreen2.kt | 17 +- .../utsmyanmar/ui/dashboard/SeeMoreScreen.kt | 141 +++++++ .../utsmyanmar/ui/navigation/AppNavGraph.kt | 34 ++ .../mob/utsmyanmar/ui/navigation/Routes.kt | 4 +- .../utsmyanmar/ui/pinpad/PinPadViewModel.kt | 10 +- .../ui/void_trace/VoidTraceScreen.kt | 354 ++++++++++++++++++ .../utsmyanmar/baselib/di/DatabaseModule.java | 90 +---- gradle/libs.versions.toml | 2 + 13 files changed, 628 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/com/mob/utsmyanmar/ui/dashboard/SeeMoreScreen.kt create mode 100644 app/src/main/java/com/mob/utsmyanmar/ui/void_trace/VoidTraceScreen.kt diff --git a/.gitignore b/.gitignore index ef995b8..681a57c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ local.properties /.idea /.idea +/sunmiui-lib +/paysdk-lib diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 51d4bab..263ebcc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -47,6 +47,7 @@ dependencies { implementation(libs.androidx.compose.foundation) implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.runtime) + implementation(libs.androidx.compose.runtime.livedata) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.tooling.preview) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountRoute.kt index 6290f41..6e70e9f 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountRoute.kt @@ -13,17 +13,77 @@ fun AmountRoute( onNavigateCardWaiting: () -> Unit ) { AmountScreen( + title = action.ifBlank { "Amount" }, onBackClick = onBack, onChargeClick = { amount -> sharedViewModel.amount.value = amount sharedViewModel.setAmountExist(true) sharedViewModel.setCardDataExist(false) sharedViewModel.setTransMenu(null) - sharedViewModel.transactionsType.value = TransactionsType.SALE - sharedViewModel.processCode.value = - ProcessCode.SALE_PURCHASE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + val config = action.toTransactionConfig() + sharedViewModel.transactionName.value = config.transactionName + sharedViewModel.transactionsType.value = config.transactionType + sharedViewModel.processCode.value = config.processCode onNavigateCardWaiting() } ) } + +private data class TransactionConfig( + val transactionName: String, + val transactionType: TransactionsType, + val processCode: String +) + +private fun String.toTransactionConfig(): TransactionConfig { + return when (trim().lowercase()) { + "void" -> TransactionConfig( + transactionName = "SALE", + transactionType = TransactionsType.VOID, + processCode = ProcessCode.SALE_VOID + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + "refund" -> TransactionConfig( + transactionName = "REFUND", + transactionType = TransactionsType.REFUND, + processCode = ProcessCode.REFUND + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + "pre-auth" -> TransactionConfig( + transactionName = "PRE_AUTH", + transactionType = TransactionsType.PRE_AUTH_SALE, + processCode = ProcessCode.PRE_AUTH_SALE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + "pre-auth void" -> TransactionConfig( + transactionName = "PRE_AUTH", + transactionType = TransactionsType.PRE_AUTH_VOID, + processCode = ProcessCode.PRE_AUTH_VOID + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + "pre-auth complete" -> TransactionConfig( + transactionName = "PRE_AUTH_COMPLETE", + transactionType = TransactionsType.PRE_AUTH_COMPLETE, + processCode = ProcessCode.PRE_AUTH_COMPLETE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + "pre-auth complete void" -> TransactionConfig( + transactionName = "PRE_AUTH_COMPLETE", + transactionType = TransactionsType.PRE_AUTH_COMPLETE_VOID, + processCode = ProcessCode.PRE_AUTH_COMPLETE_VOID + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + "cash out" -> TransactionConfig( + transactionName = "CASH_OUT", + transactionType = TransactionsType.CASH_OUT, + processCode = ProcessCode.CASH_ADVANCE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + + else -> TransactionConfig( + transactionName = "SALE", + transactionType = TransactionsType.SALE, + processCode = ProcessCode.SALE_PURCHASE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT + ) + } +} diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountScreen.kt index 99d5b99..47f0b02 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/amount/AmountScreen.kt @@ -22,6 +22,7 @@ import com.mob.utsmyanmar.ui.theme.Color @Composable fun AmountScreen( + title: String = "Amount", onBackClick: () -> Unit = {}, onChargeClick: (String) -> Unit = {} ) { @@ -59,7 +60,7 @@ fun AmountScreen( } Text( - text = "Amount", + text = title, color = Color.LegacyRed, fontSize = 14.sp, fontWeight = FontWeight.Bold @@ -69,7 +70,7 @@ fun AmountScreen( Spacer(modifier = Modifier.height(36.dp)) Text( - text = "Enter Amount", + text = "Enter $title", color = Color.Gray, fontSize = 11.sp, modifier = Modifier.align(Alignment.CenterHorizontally) @@ -100,7 +101,7 @@ fun AmountScreen( Spacer(modifier = Modifier.height(12.dp)) Text( - text = "Enter the amount to charge", + text = "Enter the amount to continue", color = Color.Gray, fontSize = 11.sp, modifier = Modifier.align(Alignment.CenterHorizontally) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/cardwaiting/CardWaitingScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/cardwaiting/CardWaitingScreen.kt index 483ae67..025c5fd 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/cardwaiting/CardWaitingScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/cardwaiting/CardWaitingScreen.kt @@ -224,7 +224,7 @@ private fun CardWaitingScreenContent( Spacer(modifier = Modifier.height(18.dp)) - StatusPanel(uiState = uiState) +// StatusPanel(uiState = uiState) Spacer(modifier = Modifier.weight(1f)) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt index c4a6185..fbb2fb8 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt @@ -84,6 +84,7 @@ import kotlinx.coroutines.launch fun DashboardScreen2( onNavigateAmount: (String) -> Unit = {}, onNavigateSignOn: () -> Unit = {}, + onNavigateSeeMore: () -> Unit = {}, deviceInfoViewModel: DeviceInfoViewModel = viewModel() ) { val deviceInfo by deviceInfoViewModel.uiState.collectAsState() @@ -91,8 +92,7 @@ fun DashboardScreen2( LaunchedEffect(Unit) { deviceInfoViewModel.loadDeviceInfo(); } - val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Open) //for preview -// val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Closed) //for normal usage + val drawerState = rememberDrawerState(initialValue = androidx.compose.material3.DrawerValue.Closed) val scope = rememberCoroutineScope() val mainHandler = remember { Handler(Looper.getMainLooper()) } var showHostActionDialog by remember { mutableStateOf(false) } @@ -300,7 +300,8 @@ fun DashboardScreen2( Spacer(modifier = Modifier.height(16.dp)) MenuGrid( onNavigateAmount = onNavigateAmount, - onNavigateSignOn = onNavigateSignOn + onNavigateSignOn = onNavigateSignOn, + onNavigateSeeMore = onNavigateSeeMore ) } } @@ -494,7 +495,8 @@ private fun IconCircle( @Composable private fun MenuGrid( onNavigateAmount: (String) -> Unit, - onNavigateSignOn: () -> Unit + onNavigateSignOn: () -> Unit, + onNavigateSeeMore: () -> Unit ) { Column( verticalArrangement = Arrangement.spacedBy(10.dp), @@ -519,7 +521,12 @@ private fun MenuGrid( onClick = onNavigateSignOn ) MenuCard("Settlement", Icons.Default.Wallet, Modifier.weight(1f)) - MenuCard("See More", Icons.Default.GridView, Modifier.weight(1f)) + MenuCard( + "See More", + Icons.Default.GridView, + Modifier.weight(1f), + onClick = onNavigateSeeMore + ) } } } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/SeeMoreScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/SeeMoreScreen.kt new file mode 100644 index 0000000..daf798f --- /dev/null +++ b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/SeeMoreScreen.kt @@ -0,0 +1,141 @@ +package com.mob.utsmyanmar.ui.dashboard + +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.PaddingValues +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.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.AccountBalanceWallet +import androidx.compose.material.icons.filled.CreditCard +import androidx.compose.material.icons.filled.Lock +import androidx.compose.material.icons.filled.LockOpen +import androidx.compose.material.icons.filled.Replay +import androidx.compose.material.icons.filled.SwapHoriz +import androidx.compose.material.icons.filled.Undo +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.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +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.theme.Color + +@Composable +fun SeeMoreScreen( + onBack: () -> Unit = {}, + onNavigateAmount: (String) -> Unit = {} +) { + val items = listOf( + SeeMoreItem("Void", Icons.Default.Undo), + SeeMoreItem("Refund", Icons.Default.Replay), + SeeMoreItem("Pre-Auth", Icons.Default.Lock), + SeeMoreItem("Pre-Auth Void", Icons.Default.LockOpen), + SeeMoreItem("Pre-Auth Complete", Icons.Default.CreditCard), + SeeMoreItem("Pre-Auth Complete Void", Icons.Default.SwapHoriz), + SeeMoreItem("Cash Out", Icons.Default.AccountBalanceWallet) + ) + + Scaffold( + containerColor = Color.IvoryBeige, + topBar = { + AppBar( + title = "See More", + icon = Icons.AutoMirrored.Filled.ArrowBack, + onIconClick = onBack + ) + } + ) { paddingValues -> + LazyVerticalGrid( + columns = GridCells.Fixed(2), + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + contentPadding = PaddingValues(16.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(items) { item -> + MoreMenuCard( + title = item.title, + icon = item.icon, + onClick = { onNavigateAmount(item.title) } + ) + } + } + } +} + +@Composable +private fun MoreMenuCard( + title: String, + icon: ImageVector, + onClick: () -> Unit +) { + Card( + modifier = Modifier + .fillMaxWidth() + .height(132.dp) + .clickable(onClick = onClick), + shape = RoundedCornerShape(18.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(4.dp) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(14.dp), + verticalArrangement = Arrangement.SpaceBetween + ) { + Box( + modifier = Modifier + .background(Color.CrimsonRed, RoundedCornerShape(14.dp)) + .padding(12.dp) + ) { + Icon( + imageVector = icon, + contentDescription = title, + tint = Color.White + ) + } + + Text( + text = title, + color = Color.Black, + fontSize = 14.sp, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Start + ) + } + } +} + +private data class SeeMoreItem( + val title: String, + val icon: ImageVector +) + +@P2Preview +@Composable +private fun PreviewSeeMoreScreen() { + SeeMoreScreen() +} diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index 78c5d54..c329725 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -15,6 +15,7 @@ import com.mob.utsmyanmar.ui.amount.AmountRoute import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2 +import com.mob.utsmyanmar.ui.dashboard.SeeMoreScreen import com.mob.utsmyanmar.ui.pinpad.PinPadRoute import com.mob.utsmyanmar.ui.processing_card.ProcessingCardRoute import com.mob.utsmyanmar.ui.processing_card.ProcessingCardViewModel @@ -23,6 +24,7 @@ import com.mob.utsmyanmar.ui.sign_on.SignOnResultScreen import com.mob.utsmyanmar.ui.sign_on.SignOnRoute import com.mob.utsmyanmar.ui.sending_to_host.SendingToHostRoute import com.mob.utsmyanmar.ui.transaction_result.TransactionResultRoute +import com.mob.utsmyanmar.ui.void_trace.VoidTraceScreen import com.mob.utsmyanmar.viewmodel.CardReaderViewModel import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel import com.mob.utsmyanmar.ui.pinpad.PinPadViewModel @@ -54,10 +56,41 @@ fun AppNavGraph( navController.navigate(Routes.SignOn.route) { launchSingleTop = true } + }, + onNavigateSeeMore = { + navController.navigate(Routes.SeeMore.route) { + launchSingleTop = true + } } ) } + composable(Routes.SeeMore.route) { + SeeMoreScreen( + onBack = { navController.popBackStack() }, + onNavigateAmount = { action -> + if (action == "Void") { + navController.navigate(Routes.VoidTrace.route) { + launchSingleTop = true + } + } else { + navController.navigate(Routes.Amount.createRoute(action)) { + launchSingleTop = true + } + } + } + ) + } + + composable(Routes.VoidTrace.route) { + val sharedViewModel: SharedViewModel = hiltViewModel(activity) + + VoidTraceScreen( + sharedViewModel = sharedViewModel, + onBack = { navController.popBackStack() } + ) + } + composable(Routes.SignOn.route) { SignOnRoute( onBack = { navController.popBackStack() }, @@ -187,6 +220,7 @@ fun AppNavGraph( ProcessingCardRoute( viewModel = processingCardViewModel, onNavigatePinPad = { + pinPadViewModel.resetSessionState() navController.navigate(Routes.PinPad.route) { popUpTo(Routes.ProcessingCard.route) { inclusive = true diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt index c9d64de..b26e6b3 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/Routes.kt @@ -5,8 +5,10 @@ import android.net.Uri sealed class Routes(val route: String) { data object Dashboard : Routes("dashboard") data object Amount : Routes("amount/{action}") { - fun createRoute(action: String): String = "amount/$action" + fun createRoute(action: String): String = "amount/${Uri.encode(action)}" } + data object SeeMore : Routes("see_more") + data object VoidTrace : Routes("void_trace") data object SignOn : Routes("sign_on") data object SignOnResult : Routes("sign_on_result/{isSuccess}/{message}") { fun createRoute(isSuccess: Boolean, message: String): String { diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt index 67c417f..d76d71f 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt @@ -116,6 +116,13 @@ class PinPadViewModel @Inject constructor( _transType.value = type } + fun resetSessionState() { + _pinText.value = "" + _alertMsg.value = null + _errorCode.value = null + _pinStatus.value = null + } + /* * Pin Pad */ @@ -123,7 +130,8 @@ class PinPadViewModel @Inject constructor( fun startPinPadProcess( customPinPadKeyboard: CustomPinPadKeyboard ) { - + resetSessionState() + // dukptIndex = SystemParamsOperation.getInstance().tmkIndex.toInt() if(!sunmiPayManager.isReady()){ _alertMsg.value = diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/void_trace/VoidTraceScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/void_trace/VoidTraceScreen.kt new file mode 100644 index 0000000..07e1e1c --- /dev/null +++ b/app/src/main/java/com/mob/utsmyanmar/ui/void_trace/VoidTraceScreen.kt @@ -0,0 +1,354 @@ +package com.mob.utsmyanmar.ui.void_trace + +import android.util.Log +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.filled.ArrowBack +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.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.livedata.observeAsState +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.style.TextAlign +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import com.mob.utsmyanmar.ui.components.appbar.AppBar +import com.mob.utsmyanmar.ui.theme.Color +import com.mob.utsmyanmar.viewmodel.SharedViewModel +import com.utsmyanmar.paylibs.model.PayDetail +import com.utsmyanmar.paylibs.utils.POSUtil +import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType + +@Composable +fun VoidTraceScreen( + sharedViewModel: SharedViewModel, + onBack: () -> Unit = {} +) { + val tag = "VoidTraceScreen" + var traceNumber by remember { mutableStateOf("") } + var searchedTrace by remember { mutableStateOf("") } + val recentTransactions by sharedViewModel.getLastThreeTransactions().observeAsState(emptyList()) + + val transactionSource: LiveData = remember(searchedTrace) { + if (searchedTrace.isBlank()) { + MutableLiveData(null) + } else { + MutableLiveData(null) + } + } + val transaction by transactionSource.observeAsState() + val hasSearched = searchedTrace.isNotBlank() + val headerMessage = if (hasSearched && transaction == null) { + "Warning: no previous sale transaction found for trace $searchedTrace." + } else { + "Input trace number to find previous sale transaction." + } + val headerColor = if (hasSearched && transaction == null) { + Color.LegacyRed + } else { + Color.Black + } + + LaunchedEffect(recentTransactions) { + Log.d( + tag, + "Recent DB traces: ${ + recentTransactions.joinToString { detail -> + "${detail.voucherNo}:${detail.transType}:${detail.tradeAnswerCode}" + } + }" + ) + } + + LaunchedEffect(searchedTrace, transaction) { + if (searchedTrace.isNotBlank()) { + Log.d( + tag, + "Search trace=$searchedTrace result=${transaction?.voucherNo ?: "NOT_FOUND"}" + ) + } + } + + Scaffold( + containerColor = Color.IvoryBeige, + topBar = { + AppBar( + title = "Void", + icon = Icons.AutoMirrored.Filled.ArrowBack, + onIconClick = onBack + ) + } + ) { paddingValues -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp) + ) { + Text( + text = headerMessage, + color = headerColor, + fontSize = 14.sp + ) + + Spacer(modifier = Modifier.height(28.dp)) + + Text( + text = "Trace Number", + color = Color.Gray, + fontSize = 11.sp, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = traceNumber.ifEmpty { "000000" }, + color = Color.LegacyRed, + fontSize = 32.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "Enter 6-digit trace number", + color = Color.Gray, + fontSize = 11.sp, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + + Spacer(modifier = Modifier.height(24.dp)) + + TraceNumberKeypad( + onNumberClick = { value -> + if (traceNumber.length < 6) { + traceNumber = (traceNumber + value).take(6) + } + } + ) + + Spacer(modifier = Modifier.height(20.dp)) + + Column(modifier = Modifier.weight(1f)) { + if (transaction != null) { + TransactionDetailsCard(transaction = transaction!!) + } + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 18.dp), + 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 = { + searchedTrace = traceNumber + }, + modifier = Modifier + .weight(1f) + .height(56.dp), + enabled = traceNumber.isNotBlank(), + shape = RoundedCornerShape(8.dp), + colors = ButtonDefaults.buttonColors( + containerColor = Color.LegacyRed, + contentColor = Color.White, + disabledContainerColor = Color.LegacyRed.copy(alpha = 0.5f), + disabledContentColor = Color.White + ) + ) { + Text("Enter") + } + } + } + + Card( + modifier = Modifier + .align(Alignment.TopEnd) + .padding(top = 110.dp, end = 16.dp) + .clickable(enabled = traceNumber.isNotEmpty()) { + traceNumber = traceNumber.dropLast(1) + }, + shape = RoundedCornerShape(18.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 6.dp) + ) { + androidx.compose.material3.Icon( + imageVector = Icons.Rounded.Backspace, + contentDescription = "Delete", + tint = if (traceNumber.isNotEmpty()) Color.LegacyRed else Color.Gray, + modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp) + ) + } + } + } +} + +@Composable +private fun TraceNumberKeypad( + onNumberClick: (String) -> Unit +) { + val keys = 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 -> + if (key.isBlank()) { + Spacer( + modifier = Modifier + .weight(1f) + .height(66.dp) + ) + } else { + TraceKeypadButton( + text = key, + modifier = Modifier.weight(1f), + onClick = { onNumberClick(key) } + ) + } + } + } + } + } +} + +@Composable +private fun TraceKeypadButton( + text: String, + modifier: Modifier = Modifier, + onClick: () -> Unit +) { + 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 { onClick() }, + contentAlignment = Alignment.Center + ) { + Text( + text = text, + color = Color.LegacyRed, + fontSize = 24.sp, + fontWeight = FontWeight.Normal, + textAlign = TextAlign.Center + ) + } +} + +@Composable +private fun TransactionDetailsCard(transaction: PayDetail) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = Color.White) + ) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(10.dp) + ) { + Text( + text = "Previous Sale", + color = Color.LegacyRed, + fontWeight = FontWeight.Bold, + fontSize = 16.sp + ) + + DetailRow("Trace", transaction.voucherNo) + DetailRow("Amount", POSUtil.getInstance().formatAmount(transaction.amount)) + DetailRow("Card No", transaction.cardNo) + DetailRow("Reference", transaction.referNo) + DetailRow("Approval", transaction.approvalCode.orEmpty()) + DetailRow("Date", transaction.tradeDate) + DetailRow("Time", transaction.tradeTime) + } + } +} + + +@Composable +private fun DetailRow( + label: String, + value: String +) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = label, + color = Color.Gray, + fontSize = 13.sp + ) + Text( + text = value.ifBlank { "-" }, + color = Color.Black, + fontSize = 13.sp, + fontWeight = FontWeight.Medium + ) + } +} diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java b/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java index cba21ea..ef2e499 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java @@ -60,7 +60,7 @@ public class DatabaseModule { private static final String DATABASE_KEY_ALIAS = "RoomDatabaseKeyAlias"; // Alias for the database key in Android Keystore private static final String ANDROID_KEYSTORE = "AndroidKeyStore"; - private static final String DATABASE_NAME = "yoma"; + private static final String DATABASE_NAME = "mob"; static final Migration MIGRATION_7_8 = new Migration(7, 8) { @Override @@ -422,67 +422,6 @@ public class DatabaseModule { } }) .build(); -// if (INSTANCE == null) { -// synchronized (AppDatabase.class) { -// if (INSTANCE == null) { -// try { -// // Step 1: Try to get the database key -// byte[] databaseKey = getDatabaseKey(application.getApplicationContext()); -// -// // Create the SQLCipher factory with the key -// SupportSQLiteOpenHelper.Factory factory = new SupportFactory(databaseKey); -// -// // Try to build and open the database -// try { -// INSTANCE = Room.databaseBuilder(application, -// AppDatabase.class, DATABASE_NAME) -// .openHelperFactory(factory) -// .addMigrations(MIGRATION_7_8) -// .addMigrations(MIGRATION_8_9) -// .addMigrations(MIGRATION_9_10) -// .addMigrations(MIGRATION_10_11) -// .addMigrations(MIGRATION_11_12) -// .allowMainThreadQueries() -// .build(); -// -// // Validate the database connection by performing a simple query -// // This will throw an exception if the key is wrong -// INSTANCE.getOpenHelper().getWritableDatabase(); -// LogUtil.d("Database", "Database opened successfully with encryption key"); -// } catch (Exception e) { -// LogUtil.e("Database", "Error opening encrypted database: " + e.getMessage()+ e); -// -// // The key might be wrong - check if this is a first-time issue or a key mismatch -// if (isDatabaseFileCorruptOrWrongKey(application)) { -// LogUtil.w("Database", "Database file exists but can't be opened with current key. Recreating database."); -// -// // Delete the existing database file -// handleDatabaseRecreation(application); -// -// // Create a new database with the current key -// INSTANCE = Room.databaseBuilder(application, -// AppDatabase.class, DATABASE_NAME) -// .openHelperFactory(factory) -// .addMigrations(MIGRATION_7_8) -// .addMigrations(MIGRATION_8_9) -// .addMigrations(MIGRATION_9_10) -// .addMigrations(MIGRATION_10_11) -// .addMigrations(MIGRATION_11_12) -// .allowMainThreadQueries() -// .build(); -// } else { -// // If it's not a key issue, rethrow the exception -// throw e; -// } -// } -// } catch (Exception e) { -// LogUtil.e("Database", "Critical error initializing database: " + e.getMessage()+ e); -// throw new RuntimeException("Failed to initialize the database", e); -// } -// } -// } -// } -// return INSTANCE; } @@ -527,32 +466,7 @@ public class DatabaseModule { .putLong("db_recreated_time", System.currentTimeMillis()) .apply(); } - -// return Room.databaseBuilder(application, AppDatabase.class,"yoma") -//// .fallbackToDestructiveMigration() -// .addMigrations(MIGRATION_7_8) -// .addMigrations(MIGRATION_8_9) -// .addMigrations(MIGRATION_9_10) -// .addMigrations(MIGRATION_10_11) -// .addMigrations(MIGRATION_11_12) -// .allowMainThreadQueries() -// .addCallback(new RoomDatabase.Callback() { -// @Override -// public void onCreate(@NonNull SupportSQLiteDatabase db) { -// super.onCreate(db); -// Executors.newSingleThreadScheduledExecutor().execute(new Runnable() { -// @Override -// public void run() { -// -// /* -// * init here -// * */ -// } -// }); -// } -// }) -// .build(); -// } + @Provides @Singleton diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 158b468..e4fe310 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ runtime = "1.11.1" rxandroid = "3.0.2" rxjava = "3.1.12" hiltNavigationCompose = "1.2.0" +runtimeLivedata = "1.11.2" [libraries] androidx-compose-material-icons-core = { module = "androidx.compose.material:material-icons-core" } @@ -51,6 +52,7 @@ retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" } rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" } androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" } +androidx-compose-runtime-livedata = { group = "androidx.compose.runtime", name = "runtime-livedata", version.ref = "runtimeLivedata" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }