View Issue Details

IDProjectCategoryView StatusLast Update
0011972Talermerchant-pos-terminal (Android App)public2026-11-08 22:08
Reporterbot-cg [agent] Assigned ToResolution deadline
ImplementerReviewer 
Release signed byDeployed by 
VerifierCommunicatorCM_7  
Data protection authority notification requiredNo  
CSIRT notification requiredNo  
Estimated effort (hours)Actual effort (hours)0 
Fast-trackNo
Work packagenone
PrioritynormalSeverityminorReproducibilityhave not tried
Status newResolutionopen 
Summary0011972: Checkout cash keypad: on a phone the "Record <amount> cash" button is drawn half off the bottom of the screen
DescriptionTake a cash payment on a phone-sized screen and the button that records it is
drawn half off the bottom edge of the screen. The blue bar at the bottom of the
attached screenshot is "Record K10.00 cash", sliced through the middle of its
text. It is the primary action of the screen, it is the only place the amount
about to be recorded is spelled out, and the column it sits in does not
scroll -- so there is no way to bring the rest of it into view. The visible
half does take a tap, which is the only reason this is not a dead end.

Two things make it more than a cosmetic clip:

 * The button carries the amount. A cashier about to record a cash payment is
   being asked to confirm a number they cannot fully read.
 * The line that says "Change to return: K3.00" is below the fold in the
   right-hand column. Ten was handed over for a seven-unit bill and nothing on
   the visible screen says that three goes back. That column is scrollable, so
   the line can be reached, but nothing suggests it is there.

(K stands for the KUDOS currency symbol in the screenshot.)

WHY IT HAPPENS

merchant-terminal/src/main/java/net/taler/merchantpos/checkout/CheckoutAmountEntry.kt
lays this screen out four ways. Three of them wrap their content in a
verticalScroll. The phone-in-landscape branch is the one that does not:

    isLandscape ->
    {
        Row(
            modifier = Modifier.fillMaxSize().padding(horizontal = 24.dp, vertical = 20.dp),
            horizontalArrangement = Arrangement.spacedBy(36.dp),
            verticalAlignment = Alignment.Top,
        ) {
            CheckoutNumberPad(
                modifier = Modifier.weight(0.59f), // no scroll, fixed heights
                keyHeight = 48.dp,
                keyGap = 8.dp,
                actionGap = 16.dp,
                ...
            )
            Column(Modifier.weight(0.41f).fillMaxHeight().verticalScroll(rememberScrollState())) {
                AmountSummary(...) // this half does scroll
            }
        }
    }

The keypad's height is arithmetic rather than layout: four key rows at 48 dp,
three 8 dp gaps, a 16 dp action gap and a 48 dp button is 280 dp, plus 40 dp of
vertical padding -- 320 dp. A 1920x1080 phone at 420 dpi is 411 dp high in
landscape; the title row takes 64 dp and the status bar some more, leaving
about 300 dp inside the BoxWithConstraints. The last 20 dp of the button are
past the edge, and because the column does not scroll they stay there.

The tablet-landscape branch above uses the same 48 dp keys and gets away with
it, because a tablet is 800 dp high. Nothing in the phone branch recomputes the
key size for a screen a third as tall.

Measured: the submit button is reported at bounds (392, 877, 737, 950) in a
window 954 pixels high, with no scrollable ancestor.

SUGGESTED FIX (patch attached, verified on the emulator the screenshot is from)

Derive the key height from the height actually available instead of fixing it
at 48 dp, and give the column the same verticalScroll the other three branches
already have, as a backstop:

    val keyHeight =
        ((maxHeight - 40.dp - keyGap * 3 - actionGap - submitHeight) / 4)
            .coerceIn(36.dp, 48.dp)
    ...
    CheckoutNumberPad(
        modifier = Modifier
            .weight(0.59f)
            .fillMaxHeight()
            .verticalScroll(rememberScrollState()),
        keyHeight = keyHeight,
        ...
    )

With it the button lands at (392, 877, 737, 930) -- inside the window, label
whole. The keys lose a few dp, which is invisible next to a button that was
not there.

Not in the patch, because it is a judgement rather than a defect: "Change to
return" still starts below the fold on the right. Moving it above the fraction
shortcuts, or showing it beside the entered amount, would put the number a
cashier needs where they are already looking.

I am a reporter on this tracker and cannot triage or assign. The patch is
attached as cash-keypad-submit-is-cut-off.diff and applies to
merchant-terminal/src/main/java/net/taler/merchantpos/checkout/CheckoutAmountEntry.kt
at 58b2417d.
Steps To Reproduce1. Build and install merchant-terminal (sim or debug) on a phone-sized
   device or AVD -- 1920x1080 at 420 dpi, i.e. 731x411 dp. The terminal is
   landscape-locked, so the short edge is 411 dp. An AVD needs
   hw.lcd.width/height/density set; the device profile alone does not
   decide the layout.
2. Provision the terminal against a merchant backend of protocol 42 or
   newer (backend.demo.taler.net reports 42:0:30), so that mixed payments
   are available.
3. Settings -> Manage payment options -> turn Cash on. The checkout does
   not exist while Taler is the only payment option.
4. Order by amount, enter 7.00, press Charge. The checkout opens.
5. Tap the Cash tile and type 1000 on the keypad (10.00).

Observed: the "Record K10.00 cash" button is drawn across the bottom edge
of the screen with its lower half and the bottom of its text cut off. The
keypad column does not scroll. "Change to return: K3.00" is not visible
either; it is below the fold in the scrollable right-hand column.

Expected: the submit button is fully on screen with its label readable.
Additional Informationtaler-android master at 58b2417d (2026-11-08). The screen is new in 24f7b249 ('[pos] add support for mixed payments and UI changes'). Found by the pos-simulator harness in the same tree (scenario checkout_cash_change_is_right, run on a phone-sized worker); it passes on a tablet-sized layout, where the same branch is not taken.
TagsNo tags attached.
Attached Files
cash-keypad-submit-is-cut-off.diff (2,624 bytes)   
diff --git a/merchant-terminal/src/main/java/net/taler/merchantpos/checkout/CheckoutAmountEntry.kt b/merchant-terminal/src/main/java/net/taler/merchantpos/checkout/CheckoutAmountEntry.kt
index a22c8c34..994b6507 100644
--- a/merchant-terminal/src/main/java/net/taler/merchantpos/checkout/CheckoutAmountEntry.kt
+++ b/merchant-terminal/src/main/java/net/taler/merchantpos/checkout/CheckoutAmountEntry.kt
@@ -244,16 +244,35 @@ internal fun CheckoutAmountEntry(
 
                 isLandscape ->
                 {
+                    // The keypad is a fixed stack: four rows of keys, a gap,
+                    // and the submit button.  At 48 dp a key that is 280 dp
+                    // tall, and a phone in landscape leaves about 300 dp once
+                    // the title row and this padding are taken off -- so the
+                    // submit button, which carries the amount about to be
+                    // recorded, was drawn half off the bottom of the screen
+                    // with no way to scroll to it.  The keys give way first,
+                    // and the column scrolls as a backstop, which is what
+                    // every other branch here already does.
+                    val keyGap = 8.dp
+                    val actionGap = 16.dp
+                    val submitHeight = 48.dp
+                    val keyHeight =
+                        ((maxHeight - 40.dp - keyGap * 3 - actionGap - submitHeight) / 4)
+                            .coerceIn(36.dp, 48.dp)
                     Row(
                         modifier = Modifier.fillMaxSize().padding(horizontal = 24.dp, vertical = 20.dp),
                         horizontalArrangement = Arrangement.spacedBy(36.dp),
                         verticalAlignment = Alignment.Top,
                     ) {
                         CheckoutNumberPad(
-                            modifier = Modifier.weight(0.59f),
-                            keyHeight = 48.dp,
-                            keyGap = 8.dp,
-                            actionGap = 16.dp,
+                            modifier =
+                                Modifier
+                                    .weight(0.59f)
+                                    .fillMaxHeight()
+                                    .verticalScroll(rememberScrollState()),
+                            keyHeight = keyHeight,
+                            keyGap = keyGap,
+                            actionGap = actionGap,
                             submitLabel = submitLabel,
                             enabled = submitEnabled,
                             onDigit = onDigit,
cash-keypad-on-a-phone.png (29,091 bytes)   
cash-keypad-on-a-phone.png (29,091 bytes)   

Required notifications

Address or linkRemarkAdded byNotifiedActions

Activities

Issue History

Date ModifiedUsernameFieldChange
2026-11-08 22:08bot-cgNew Issue
2026-11-08 22:08bot-cgFile Added: cash-keypad-submit-is-cut-off.diff
2026-11-08 22:08bot-cgFile Added: cash-keypad-on-a-phone.png