forked from thijooree/android
109 lines
7.0 KiB
Markdown
109 lines
7.0 KiB
Markdown
# PayMV QR Screen
|
||
|
||
Generates a receive-payment PayMV / Favara QR code. **Generation only** — the send/scan side of PayMV lives in `TransferFragment` via `newInstanceWithAutoScan()` and the [QR scanner](25-qr-scanner.md).
|
||
|
||
> **Fahipay QRs are a work in progress.** Thijooree's Fahipay card matches Fahipay's design, but the Fahipay app currently rejects the QRs it generates as **"Invalid QR"**. BML QRs scan fine. See [PayMV QR Format → Fahipay](18-paymv-qr-format.md#fahipay-work-in-progress).
|
||
|
||
---
|
||
|
||
## Fragment — `PayMvQrFragment`
|
||
|
||
A single screen (no tabs). Re-renders the QR live (300 ms debounce) as the user edits the form. It can also be opened for a saved contact with `PayMvQrFragment.forContact(accountNumber, name, bank)`. The QR then pays into the contact's account, and the account picker and phone toggle are hidden.
|
||
|
||
### Fields
|
||
|
||
| Field | Source / behaviour |
|
||
|---|---|
|
||
| Source account dropdown | `viewModel.accounts`, filtered to non-card MVR accounts (MIB, M-Faisa and BML USD currently excluded — flagged as TODO in source). Defaults to `CredentialStore.getDefaultAccountNumber()` when set |
|
||
| Amount (`etAmount`) | Optional. Blank / zero / unparseable → open-amount QR. Commas are stripped |
|
||
| Reference (`etReference`) | Free-text purpose, written to tag 62→08. Blank → tag omitted (BML), or `PAYMENT` (Fahipay) |
|
||
| Include phone (`switchIncludePhone`) | When on, writes the saved BML / Fahipay mobile to sub-tag 26→05, normalised to `+960XXXXXXX` |
|
||
|
||
### What goes on the card
|
||
|
||
| Item | Value |
|
||
|---|---|
|
||
| Name | BML / MIB: `accountBriefName`. Fahipay: the holder's full name (`profileName`, falling back to the saved Fahipay profile's `fullName`) — **not** the generic "Fahipay Wallet" brief name. Contacts: the contact's name. Always uppercased |
|
||
| QR | The payload below, white modules on the card blue, error correction M, no quiet zone |
|
||
| Vertical text | The QR's reference (tag 62→05) — see below |
|
||
| Amount | **Not printed** on the card (neither bank does); it only appears inside the QR, and in BML's vertical text |
|
||
|
||
### Vertical text (reference)
|
||
|
||
Both banks print a short code vertically beside the QR, reading bottom-to-top. It is the same string as the payload's reference, **tag 62→05**, so Thijooree calculates the reference first and uses it for both.
|
||
|
||
| Bank | Reference / vertical text | Example |
|
||
|---|---|---|
|
||
| BML | Account number converted to **base-32** (digits `0-9A-V`, uppercase), followed by the **amount exactly as typed** (commas removed, no forced decimals), capped at 25 chars | `7730000188362` → `70V3UKKUA`; with amount `100` → `70V3UKKUA100` |
|
||
| Fahipay | `P` + 9 random uppercase alphanumeric chars. **No amount** | `P2KVTPYL4E` |
|
||
| Other (MIB contacts) | 9 random uppercase alphanumeric chars | `WHQS0SX5O` |
|
||
|
||
BML's base-32 is `AccountNumbertoBase32` from the BML app: `BigInt(account)`, repeatedly `% 32` into the alphabet `0123456789ABCDEFGHIJKLMNOPQRSTUV`. If the account number isn't numeric, Thijooree falls back to a random 9-char reference.
|
||
|
||
---
|
||
|
||
## Card Rendering
|
||
|
||
Two renderers, chosen by the target's bank. Both return a `Bitmap` shown in `ivQrCard` (`fitCenter`) and used for Share / Save.
|
||
|
||
### BML (and MIB) — `renderQrCard()`
|
||
|
||
A 1:1 copy of BML app v2.1.47's `ReceiveCard` React Native component (decompiled from the Hermes bundle). All values are BML's StyleSheet values in dp, laid out for a 560 dp reference screen width (`SCREEN_WIDTH_DP`) and drawn at 2 px/dp (`PX_PER_DP`), so the card comes out about 1024 px wide.
|
||
|
||
| Element | Spec |
|
||
|---|---|
|
||
| Colour | `mmaBlue` `#0E5CA4` everywhere |
|
||
| Card | Width `sw − 48`. Blue background, radius 20. The white top section is inset 2 dp (top corners 18), which shows as a thin blue border |
|
||
| Header row | 32 dp from top, 40 dp side margins. Left: `bml_logo_paymv` ("BANK OF MALDIVES" wordmark, from BML's assets) contained in `0.38·sw × 0.38·sw·0.1117`. Right: "PayMV QR", Sofia Pro Bold, `#0E5CA4`, sized to BML's `0.2·sw × 0.2·sw·0.1733` image box, shifted down 1 dp. MIB uses `mib_faisanet_logo` in the same box |
|
||
| QR panel | 24 dp below the header, 40 dp side margins, radius 16, 24 dp bottom margin |
|
||
| Name | Roboto (system default) regular, 14 sp, white; 8 + 12 dp above, 16 dp below |
|
||
| QR | `0.5·sw` square; 37 dp padding below |
|
||
| Vertical text | Roboto 10 sp, **black at 80 % opacity**, rotated −90°. Centred `railW/1.37 − railW/2` right of the QR's right edge and `(qr + railW/1.5)/2` down from the QR top, where `railW = sw/1.85`. Ellipsized to `railW` |
|
||
| Footer | "MALDIVES NATIONAL QR", Sofia Pro Bold (`res/font/sofia_pro_bold.ttf`), `0.046·sw`, letter spacing 1.2 dp, 12 dp vertical padding |
|
||
|
||
### Fahipay — `renderFahipayQrCard()`
|
||
|
||
Fahipay's app doesn't draw its card; it shows an image generated by Fahipay's server (`api/app/qr/`). Thijooree copies that image's layout, measured in pixels on its **1240 × 1322** canvas. Text is sized so capital letters match the measured cap heights.
|
||
|
||
| Element | Spec |
|
||
|---|---|
|
||
| Colour | `#005DA3` |
|
||
| Card | Blue, radius 50. White area inset 6 px (top corners 44) down to y 1174. The blue below it is the footer |
|
||
| Header row | Square app icon `fahipay_logo` at (94, 94)–(163, 163), then the "FahiPay" wordmark `fahipay_logo_long` at x 178, y 104, 48 px tall — **both, side by side** |
|
||
| "PayMV QR" | Sofia Pro Bold, blue, right-aligned at x 1147, cap height 30 (cap top y 101) |
|
||
| QR panel | (166, 218)–(1074, 1126), radius 55 |
|
||
| Name | Roboto regular, white, centred at x 619, cap height 30 (cap top y 314). Shrinks to fit the panel minus 80 px |
|
||
| QR | 562 px at (338, 417) |
|
||
| Vertical text | Montserrat Regular (`res/font/montserrat_regular.ttf`), **blue**, cap height 27, rotated −90°. It sits in the **white margin right of the panel**: text starts at y 1087, baseline at x 1171 |
|
||
| Footer | "MALDIVES NATIONAL QR", Sofia Pro Bold, white, cap height 55.5 (cap top y 1220), BML's letter spacing (1.2/25.76 em) |
|
||
|
||
Fonts follow the BML card (Sofia Pro Bold, Roboto), except the vertical text, which keeps Fahipay's Montserrat.
|
||
|
||
---
|
||
|
||
## Generation
|
||
|
||
`buildQrPayload()` assembles a decimal TLV payload per the [PayMV QR Format](18-paymv-qr-format.md#generating-a-receive-payment-qr):
|
||
|
||
1. Tag 01: `11` (static). Fahipay QRs with an amount use `12` (dynamic)
|
||
2. Tag 26: GUI (`mv.favara.mpqr`), acquirer BIC ×2 — `MALBMVMV` (BML) / `MADVMVMV` (MIB) / `FAHIMVMV` (Fahipay), account number, optional mobile, `IPAY`
|
||
3. Tag 54: amount as `%.2f`. If there's no amount: omitted (BML), `***` (Fahipay)
|
||
4. Tag 59: name, uppercased, max 25 chars
|
||
5. Tag 60: Fahipay only — `LD` + 4 random digits
|
||
6. Tag 62: the reference (above) + purpose
|
||
7. Tag 80: GUI + timestamp `yyyy-MM-dd'T'HH:mm:ss.00000`
|
||
8. Appends `"6304"` and computes CRC-16/CCITT-FALSE over the full string
|
||
|
||
### Actions
|
||
|
||
- **Share** (`btnShare`) — writes `<name>_paymv_qr.png` to the cache and shares it via `FileProvider` + `ACTION_SEND`
|
||
- **Save** (`btnSave`) — writes `<name>_PayMV_QR.png` to `MediaStore.Images` / `Pictures/`
|
||
|
||
---
|
||
|
||
|
||
|
||
---
|
||
|
||
[← OTP Screen](10-otp-screen.md) **Next →** [BML QR Pay](12-bml-qr-pay.md)
|