74 lines
3.5 KiB
Markdown
74 lines
3.5 KiB
Markdown
# /pay Fallback UX Implementation
|
|
|
|
**Date:** 2026-03-29
|
|
**Commit:** `2b93236229` on `phase1-dev`
|
|
**APK:** http://192.168.0.5:8888/
|
|
|
|
## What Was Implemented
|
|
|
|
### Flow B — Fallback When Recipient Has No Linked Wallet
|
|
|
|
When a user types `/pay 10` to a recipient who hasn't linked a Cardano wallet:
|
|
|
|
1. **Address lookup happens in background** - `CardanoAddressService.lookupAddress(@recipient)` is called
|
|
2. **Not found → Show banner card** with:
|
|
- Warning icon: "⚠️ @recipient hasn't linked a Cardano wallet"
|
|
- Instructional text: "Enter their Cardano address manually:"
|
|
- Embedded editable text field with placeholder "addr1... or addr_test1..."
|
|
3. **Live validation on manual address input**:
|
|
- Must start with `addr_test1` (preprod) or `addr1` (mainnet)
|
|
- Length between 58-108 characters
|
|
- Shows inline error if invalid
|
|
- Shows green checkmark "Valid address" when valid
|
|
4. **Continue button enables** when:
|
|
- Amount is valid (≥1 ADA)
|
|
- Manual address passes validation
|
|
5. **Resolved address is passed to confirmation screen** - The `PaymentEntryNode` now passes `state.resolvedAddress` (which comes from either the lookup or manual entry) instead of the raw `recipientInput`
|
|
|
|
## Files Changed
|
|
|
|
| File | Changes |
|
|
|------|---------|
|
|
| `PaymentFlowEvents.kt` | Added `ManualAddressChanged(address: String)` event |
|
|
| `PaymentEntryState.kt` | Added `manualAddressInput`, `manualAddressError`, `resolvedAddress` fields; added `needsManualAddressEntry` computed property |
|
|
| `PaymentEntryPresenter.kt` | Handle `ManualAddressChanged` event; `validateManualAddress()` function; updated `canContinue` logic to work with manual entry |
|
|
| `PaymentEntryView.kt` | Added `ManualAddressEntryCard` composable with embedded `OutlinedTextField`; updated preview states |
|
|
| `PaymentEntryNode.kt` | Changed to pass `state.resolvedAddress` instead of `state.recipientInput` to confirmation callback |
|
|
|
|
## Flow A — Happy Path (Already Working)
|
|
|
|
When recipient HAS a linked wallet:
|
|
1. User types `/pay 10`
|
|
2. Payment form opens with recipient pre-selected from DM context
|
|
3. `CardanoAddressService.lookupAddress(@recipient)` returns the address
|
|
4. Green card shows: "✓ Address loaded from @recipient's profile" with truncated address
|
|
5. Recipient field shows Matrix user ID (read-only context)
|
|
6. Amount field pre-filled with "10"
|
|
7. Continue button enabled immediately
|
|
8. Confirmation screen shows full transaction details with fee estimate
|
|
|
|
## Amount Pre-fill
|
|
|
|
When user types `/pay 10`, the `10` is parsed by `PayCommandParser` and passed via `ParsedPayCommand.AmountOnly` or `ParsedPayCommand.WithMatrixRecipient`. The `PaymentEntryPresenter.extractPrefills()` function extracts this and pre-fills the amount field.
|
|
|
|
## Address Validation Rules
|
|
|
|
```kotlin
|
|
private fun validateManualAddress(input: String): String? {
|
|
// Must start with addr_test1 (preprod) or addr1 (mainnet)
|
|
val isTestnet = input.startsWith("addr_test1")
|
|
val isMainnet = input.startsWith("addr1") && !input.startsWith("addr_test1")
|
|
if (!isTestnet && !isMainnet) return "Address must start with addr1 or addr_test1"
|
|
if (input.length < 58) return "Address too short"
|
|
if (input.length > 108) return "Address too long"
|
|
if (!CARDANO_ADDRESS_REGEX.matches(input)) return "Invalid Cardano address format"
|
|
return null
|
|
}
|
|
```
|
|
|
|
## Testing Notes
|
|
|
|
- Build passes with warnings only (no errors)
|
|
- All existing tests pass
|
|
- Preview states updated to include manual entry scenarios
|
|
- APK served on port 8888 for install testing
|