void screen and pinpad fix
This commit is contained in:
parent
675e398aaf
commit
dbc5424aab
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,3 +15,5 @@
|
||||
local.properties
|
||||
/.idea
|
||||
/.idea
|
||||
/sunmiui-lib
|
||||
/paysdk-lib
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -224,7 +224,7 @@ private fun CardWaitingScreenContent(
|
||||
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
|
||||
StatusPanel(uiState = uiState)
|
||||
// StatusPanel(uiState = uiState)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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<PayDetail?> = 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
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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" }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user