auto width printReceiptScreen dot

This commit is contained in:
moon 2026-08-25 21:37:47 +06:30
parent 81920acc8c
commit 7ccf393793
2 changed files with 94 additions and 27 deletions

View File

@ -38,3 +38,6 @@ Mark intentional simplifications with a ponytail: comment. If the shortcut has a
Not lazy about: understanding the problem (read it fully and trace the real flow before picking a rung, a small diff you don't understand is just laziness dressed up as efficiency), input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test. Not lazy about: understanding the problem (read it fully and trace the real flow before picking a rung, a small diff you don't understand is just laziness dressed up as efficiency), input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test.
(Yes, this file also applies to agents working on the ponytail repo itself. Especially to them.) (Yes, this file also applies to agents working on the ponytail repo itself. Especially to them.)
### Don't Do This
- don't run ./grdlew

View File

@ -3,6 +3,7 @@ package com.mob.utsmyanmar.ui.print_receipt
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -32,18 +33,24 @@ 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.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.mob.utsmyanmar.ui.components.appbar.AppBar import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.history_functions.displayTransactionStatus import com.mob.utsmyanmar.ui.history_functions.displayTransactionStatus
import com.mob.utsmyanmar.ui.history_functions.displayTransactionTitle import com.mob.utsmyanmar.ui.history_functions.displayTransactionTitle
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.mob.utsmyanmar.ui.transaction_result.TransactionResultState import com.mob.utsmyanmar.ui.transaction_result.TransactionResultState
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel
import com.mob.utsmyanmar.viewmodel.SharedViewModel import com.mob.utsmyanmar.viewmodel.SharedViewModel
import com.utsmyanmar.paylibs.model.PayDetail
import com.utsmyanmar.paylibs.utils.POSUtil import com.utsmyanmar.paylibs.utils.POSUtil
import com.utsmyanmar.paylibs.utils.PrintStatus import com.utsmyanmar.paylibs.utils.PrintStatus
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -59,9 +66,32 @@ fun PrintReceiptScreen(
sharedViewModel: SharedViewModel, sharedViewModel: SharedViewModel,
onPrint: () -> Unit, onPrint: () -> Unit,
onDone: () -> Unit, onDone: () -> Unit,
onPrintFinished : () -> Unit, onPrintFinished: () -> Unit,
) { ) {
val state by transactionResultViewModel.state.collectAsStateWithLifecycle() val state by transactionResultViewModel.state.collectAsStateWithLifecycle()
val isReprint = sharedViewModel.isReprint.value ?: false
PrintReceiptContent(
state = state,
isReprint = isReprint,
onPrint = onPrint,
onDone = onDone,
onPrintFinished = onPrintFinished,
onSetPrintStatus = { sharedViewModel.setPrintStatus(it) },
onResetReprint = { sharedViewModel.isReprint.value = false },
)
}
@Composable
fun PrintReceiptContent(
state: TransactionResultState,
isReprint: Boolean,
onPrint: () -> Unit,
onDone: () -> Unit,
onPrintFinished: () -> Unit,
onSetPrintStatus: (PrintStatus) -> Unit,
onResetReprint: () -> Unit
) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val receiptOffsetY = remember { Animatable(0f) } val receiptOffsetY = remember { Animatable(0f) }
val merchant_copy_autoprint = true val merchant_copy_autoprint = true
@ -82,14 +112,11 @@ fun PrintReceiptScreen(
) )
} }
fun isReprintMode() = sharedViewModel.isReprint.value == true
fun doPrint(copy: ReceiptCopy, onFinished: (printFinished: ReceiptCopy) -> Unit) { fun doPrint(copy: ReceiptCopy, onFinished: (printFinished: ReceiptCopy) -> Unit) {
val reprint = isReprintMode() val actualCopy = if (isReprint && copy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER else copy
val actualCopy = if (reprint && copy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER else copy
currentCopy = actualCopy currentCopy = actualCopy
sharedViewModel.setPrintStatus( onSetPrintStatus(
if (actualCopy == ReceiptCopy.MERCHANT) if (actualCopy == ReceiptCopy.MERCHANT)
PrintStatus.FIRST_PRINT PrintStatus.FIRST_PRINT
else else
@ -100,7 +127,7 @@ fun PrintReceiptScreen(
isPrinting = true isPrinting = true
animatePrint() animatePrint()
isPrinting = false isPrinting = false
val upcomingCopy = if (reprint) ReceiptCopy.CUSTOMER val upcomingCopy = if (isReprint) ReceiptCopy.CUSTOMER
else if (actualCopy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER else if (actualCopy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER
else ReceiptCopy.CUSTOMER else ReceiptCopy.CUSTOMER
@ -112,14 +139,13 @@ fun PrintReceiptScreen(
} }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val reprint = isReprintMode() if (isReprint) {
if (reprint) {
currentCopy = ReceiptCopy.CUSTOMER currentCopy = ReceiptCopy.CUSTOMER
nextCopy = ReceiptCopy.CUSTOMER nextCopy = ReceiptCopy.CUSTOMER
} }
sharedViewModel.isReprint.value = false onResetReprint()
when { when {
merchant_copy_autoprint && !reprint -> doPrint(ReceiptCopy.MERCHANT) { } merchant_copy_autoprint && !isReprint -> doPrint(ReceiptCopy.MERCHANT) { }
customer_copy_autoprint -> doPrint(ReceiptCopy.CUSTOMER) { } customer_copy_autoprint -> doPrint(ReceiptCopy.CUSTOMER) { }
} }
} }
@ -209,6 +235,7 @@ fun ReceiptPreview(
copyLabel: String, copyLabel: String,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val isPreview = LocalInspectionMode.current
Column( Column(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
@ -246,7 +273,7 @@ fun ReceiptPreview(
ReceiptRow("Amount", POSUtil.getInstance().getDecimalAmountSeparatorFormat(state.payDetail?.amount?:0)) ReceiptRow("Amount", POSUtil.getInstance().getDecimalAmountSeparatorFormat(state.payDetail?.amount?:0))
ReceiptRow("Card Type", state.payDetail?.accountType.toString()) ReceiptRow("Card Type", state.payDetail?.accountType.toString())
ReceiptRow("Card No", state.payDetail?.cardNo.toString()) ReceiptRow("Card No", state.payDetail?.cardNo.toString())
ReceiptRow("Status", state.payDetail?.let(::displayTransactionStatus).orEmpty()) ReceiptRow("Status", if (isPreview) "SUCCESS" else state.payDetail?.let(::displayTransactionStatus).orEmpty())
ReceiptRow("Date", state.payDetail?.transDate.toString() ) ReceiptRow("Date", state.payDetail?.transDate.toString() )
ReceiptRow("Time", state.payDetail?.transTime.toString()) ReceiptRow("Time", state.payDetail?.transTime.toString())
ReceiptRow("Ref No", state.payDetail?.referNo.toString()) ReceiptRow("Ref No", state.payDetail?.referNo.toString())
@ -292,25 +319,62 @@ fun ReceiptRow(
@Composable @Composable
fun ReceiptDivider() { fun ReceiptDivider() {
Text( Canvas(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 10.dp), .padding(vertical = 10.dp)
text = "--------------------------------", .height(2.dp)
color = Color.Gray ) {
) // Convert dp to pixels so it scales perfectly on all screen sizes
val dotRadius = 1.5.dp.toPx()
val dotSpacing = 6.dp.toPx()
val totalWidth = size.width
var currentX = 0f
// Loop across the width of the screen and draw individual circles
while (currentX < totalWidth) {
drawCircle(
color = Color.Gray,
radius = dotRadius,
center = Offset(x = currentX, y = size.height / 2)
)
// Move X forward by the size of the dot + the space we want
currentX += (dotRadius * 2) + dotSpacing
}
}
} }
@Preview(showBackground = true, showSystemUi = true) @P2Preview
@P3Preview
@Composable @Composable
fun PreviewPrintReceiptScreen() { private fun PrintReceiptScreenPreview() {
MaterialTheme { val samplePayDetail = PayDetail().apply {
PrintReceiptScreen( merchantName = "Sample Merchant"
sharedViewModel = hiltViewModel(), terminalNo = "12345678"
transactionResultViewModel = hiltViewModel(), voucherNo = "000001"
amount = 100000
cardNo = "1234********5678"
transDate = "2023-10-27"
transTime = "10:30:00"
referNo = "123456789012"
transType = "SALE"
tradeAnswerCode = "00"
}
val sampleState = TransactionResultState(
payDetail = samplePayDetail
)
MOBPOSTheme {
PrintReceiptContent(
state = sampleState,
isReprint = false,
onPrint = {}, onPrint = {},
onDone = {}, onDone = {},
onPrintFinished = {} onPrintFinished = {},
onSetPrintStatus = {},
onResetReprint = {}
) )
} }
} }