Fixed ReprintAnyTransactions and new keyboard layout

This commit is contained in:
moon 2026-08-25 23:34:00 +06:30
parent 2ca1b5eee0
commit c45c8adf65
2 changed files with 188 additions and 24 deletions

View File

@ -46,6 +46,7 @@ internal fun displayTransactionTitle(payDetail: PayDetail): String {
internal fun isValidForReprint(payDetail: PayDetail): Boolean { internal fun isValidForReprint(payDetail: PayDetail): Boolean {
if (payDetail.transactionType == TransactionsType.SETTLEMENT.value) return false if (payDetail.transactionType == TransactionsType.SETTLEMENT.value) return false
if (payDetail.transactionType == TransactionsType.REVERSAL.value) return false
if (payDetail.transactionType == TransactionsType.WAVEPAY.value && payDetail.qrTransStatus != 1) { if (payDetail.transactionType == TransactionsType.WAVEPAY.value && payDetail.qrTransStatus != 1) {
return false return false
} }
@ -59,14 +60,8 @@ internal fun filterReprintAnyTransactions(
transactions: List<PayDetail>, transactions: List<PayDetail>,
hostType: HostType hostType: HostType
): List<PayDetail> { ): List<PayDetail> {
val yesterday = POSUtil.getInstance().yesterdayDate
val dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault())
return transactions.filter { pay -> return transactions.filter { pay ->
val transDate = parseTransDate(pay.transDate, dateFormat) ?: return@filter false if (!isValidForReprint(pay)) return@filter false
if (yesterday.compareTo(transDate) > 0) return@filter false
if (pay.transactionType == TransactionsType.SETTLEMENT.value) return@filter false
if (pay.transactionType == TransactionsType.REVERSAL.value) return@filter false
when (hostType) { when (hostType) {
HostType.MPU -> HostType.MPU ->

View File

@ -1,8 +1,13 @@
package com.mob.utsmyanmar.ui.history_functions package com.mob.utsmyanmar.ui.history_functions
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -10,11 +15,20 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.OutlinedTextField import androidx.compose.material.icons.automirrored.rounded.Backspace
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
@ -23,12 +37,27 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue 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.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.mob.utsmyanmar.ui.components.appbar.AppBar import androidx.compose.ui.unit.sp
import com.mob.utsmyanmar.ui.components.NumericKeypad
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
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
import com.utsmyanmar.paylibs.model.PayDetail import com.utsmyanmar.paylibs.model.PayDetail
import com.utsmyanmar.paylibs.utils.enums.HostType import com.utsmyanmar.paylibs.utils.enums.HostType
private val searchKeys = listOf(
listOf("1", "2", "3"),
listOf("4", "5", "6"),
listOf("7", "8", "9"),
listOf("C", "0", "\u232B")
)
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ReprintAnyTransactionScreen( fun ReprintAnyTransactionScreen(
viewModel: HistoryViewModel, viewModel: HistoryViewModel,
@ -38,6 +67,7 @@ fun ReprintAnyTransactionScreen(
) { ) {
val allTransactions by viewModel.getTransactionHistory().observeAsState(emptyList()) val allTransactions by viewModel.getTransactionHistory().observeAsState(emptyList())
var searchQuery by remember { mutableStateOf("") } var searchQuery by remember { mutableStateOf("") }
var isFocused by remember { mutableStateOf(false) }
val filtered = remember(allTransactions, hostType, searchQuery) { val filtered = remember(allTransactions, hostType, searchQuery) {
val base = filterReprintAnyTransactions(allTransactions, hostType) val base = filterReprintAnyTransactions(allTransactions, hostType)
@ -47,10 +77,32 @@ fun ReprintAnyTransactionScreen(
Scaffold( Scaffold(
containerColor = Color.IvoryBeige, containerColor = Color.IvoryBeige,
topBar = { topBar = {
AppBar( TopAppBar(
title = "Transactions", title = {
icon = Icons.AutoMirrored.Filled.ArrowBack, Column {
onIconClick = onBack Text(
text = "Reprint Transaction",
style = MaterialTheme.typography.titleMedium
)
Text(
text = hostTypeLabel(hostType),
style = MaterialTheme.typography.labelSmall,
color = Color.Gray
)
}
},
navigationIcon = {
IconButton(onClick = onBack) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
tint = Color.LegacyRed
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color.IvoryBeige
)
) )
} }
) { paddingValues -> ) { paddingValues ->
@ -58,37 +110,154 @@ fun ReprintAnyTransactionScreen(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(paddingValues) .padding(paddingValues)
.padding(16.dp) .padding(horizontal = 16.dp)
) { ) {
OutlinedTextField( SearchInputBox(
value = searchQuery, query = searchQuery,
onValueChange = { searchQuery = it }, isFocused = isFocused,
modifier = Modifier.fillMaxWidth(), onFocus = { isFocused = true }
label = { Text("Trace (6) or RRN (12)") },
singleLine = true
) )
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(8.dp))
Text(
text = "${filtered.size} transaction(s) found",
style = MaterialTheme.typography.labelSmall,
color = Color.Gray,
modifier = Modifier.padding(horizontal = 4.dp)
)
Spacer(modifier = Modifier.height(8.dp))
if (filtered.isEmpty()) { if (filtered.isEmpty()) {
Box( Box(
modifier = Modifier.fillMaxSize(), modifier = Modifier.weight(1f),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Text("No transactions found.", color = Color.Gray) Text(
text = if (allTransactions.isEmpty()) "No transactions available" else "No matching transactions",
color = Color.Gray,
style = MaterialTheme.typography.bodyMedium
)
} }
} else { } else {
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize(), modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
items(filtered, key = { "${it.voucherNo}_${it.referNo}_${it.PID}" }) { payDetail -> items(filtered, key = { "${it.voucherNo}_${it.referNo}_${it.PID}" }) { payDetail ->
HistoryTransactionCard(payDetail) { HistoryTransactionCard(payDetail) {
isFocused = false
onReprintTransaction(prepareReprintPayDetail(payDetail)) onReprintTransaction(prepareReprintPayDetail(payDetail))
} }
} }
} }
} }
AnimatedVisibility(
visible = isFocused,
enter = slideInVertically(initialOffsetY = { it }),
exit = slideOutVertically(targetOffsetY = { it })
) {
NumericKeypad(
keys = searchKeys,
modifier = Modifier
.fillMaxWidth()
.height(280.dp)
.padding(top = 8.dp),
onKeyClick = { key ->
when (key) {
"C" -> searchQuery = ""
"\u232B" -> searchQuery = searchQuery.dropLast(1)
else -> if (searchQuery.length < 12) searchQuery += key
}
}
)
}
}
}
}
@Composable
private fun SearchInputBox(
query: String,
isFocused: Boolean,
onFocus: () -> Unit,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onFocus),
colors = CardDefaults.cardColors(containerColor = Color.White),
shape = RoundedCornerShape(12.dp),
elevation = CardDefaults.cardElevation(defaultElevation = if (isFocused) 6.dp else 2.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = if (isFocused) "Trace or RRN" else "Tap to search by Trace or RRN",
style = MaterialTheme.typography.bodySmall,
color = if (isFocused) Color.LegacyRed else Color.Gray
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = query.ifEmpty { "_" },
color = Color.LegacyRed,
style = MaterialTheme.typography.headlineSmall.copy(
fontWeight = FontWeight.Bold,
letterSpacing = 2.sp
)
)
}
if (query.isNotEmpty()) {
Card(
shape = RoundedCornerShape(18.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
modifier = Modifier
.shadow(2.dp, RoundedCornerShape(18.dp))
.clickable { }
) {
Icon(
imageVector = Icons.AutoMirrored.Rounded.Backspace,
contentDescription = "Delete",
tint = Color.LegacyRed,
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp)
)
}
}
}
}
}
@P2Preview
@P3Preview
@Composable
private fun ReprintAnyTransactionScreenPreview() {
MOBPOSTheme {
Box(modifier = Modifier.height(600.dp)) {
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = Color.White)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
text = "SALE",
color = Color.LegacyRed,
style = MaterialTheme.typography.titleSmall
)
Spacer(modifier = Modifier.height(4.dp))
Text("Trace 000001", style = MaterialTheme.typography.bodySmall)
Text("RRN 123456789012", style = MaterialTheme.typography.bodySmall, color = Color.Gray)
}
}
} }
} }
} }