Skip to content

feat(tipping): send a tip to a scanned user's tip card - #1127

Merged
bmc08gt merged 2 commits into
code/cashfrom
feat/tipping
Jul 23, 2026
Merged

feat(tipping): send a tip to a scanned user's tip card#1127
bmc08gt merged 2 commits into
code/cashfrom
feat/tipping

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #1126 (feat/chat-notification-avatars). This PR's base is that branch; review/merge #1126 first, then this rebases onto code/cash.

What

End-to-end tipping: scan (or deeplink) another user's tip card, choose an amount, and send them a tip that opens the resulting DM chat with the tips list beneath it.

Coordinator (shared/tipping)

  • TippingCoordinator resolves the recipient's tip card, holds the tip selection (amount + token + send state), and runs the transfer via TransactionController.
  • Region-aware presets driven off the preferred rate (update live when the region changes) and min/max tippable amounts (min = lowest preset, max = send limit ∩ balance).
  • Send-limit enforcement; balance gating (hasGiveableBalance) mirrors the send/currency-creator dual-gating pattern.

Scanner

  • ScannableDecorator dispatch (Payable / TipCard) replacing the container's hardcoded when.
  • TipUserModal (presets, token row, slide-to-confirm) + affordability gating; no-balance routes to add-money/discover and dismisses the card.
  • Post-tip handoff into the tipped user's chat (navigateAll([Tips, Chat])) so back returns to the tips list.

Amount entry (features/tipping)

  • Custom tip-amount entry with region/currency change and below-min ("Tips Start at $X") / over-balance (add-money prompt) gating.

Wiring

  • TipCardDelegate, /tip/{userId} deeplink + routes, MainActivity LocalTipCoordinator provision, tip-card sharing, and token-selection wired for the Tip purpose.

Notes

  • Adds the foundation-layout version-catalog entry (scanner animation) and Modal.verticalArrangement (used only by TipUserModal).
  • TippingCoordinatorTest covers the send-limit / max-amount logic.

bmc08gt added 2 commits July 23, 2026 17:10
Surface counterparty avatars in chat notifications and rows:

- NotificationService loads the sender's remote avatar via Coil and
  falls back to the profile display name / social handle for TIP_DM
  senders (no device contact exists for them).
- Add displayName + image to ConversationReference so chat rows can
  render name and avatar.
- ContactAvatar crops (ContentScale.Crop) to avoid letterboxing.
- MediaItem.rendition()/url() default the preferred rendition to
  ORIGINAL, making the argument optional.
Adds the end-to-end tipping flow: scan (or deeplink) another user's tip
card, choose an amount, and send them a tip that opens the resulting DM
chat.

- TippingCoordinator (shared/tipping): resolves the recipient's tip
  card, holds the tip selection (amount + token + send state), derives
  region-aware presets and min/max (send limit ∩ balance) amounts,
  enforces the send limit, and runs the transfer via TransactionController.
- Scanner: ScannableDecorator dispatch (Payable/TipCard), TipUserModal
  (presets, token, slide-to-confirm), affordability gating, and a
  post-tip handoff into the tipped user's chat with the tips list beneath.
- Custom tip-amount entry (features/tipping) with region/currency change
  and below-min / over-balance gating (add-money prompt on insufficient).
- Session/nav wiring: TipCardDelegate, /tip/{userId} deeplink, routes,
  and MainActivity LocalTipCoordinator provision.
- Tip-card sharing via the share sheet; token-selection wired for Tip.
@github-actions github-actions Bot added area: payments Payments, transfers, intents, billing area: ui Compose UI, theme, components, resources area: scanner QR/Kikcode scanning, camera area: build-system Gradle, convention plugins, build-logic area: tokens Token accounts, balances, token info area: deeplinks Deep link handling, URL routing, and link parsing area: session type: feature New functionality labels Jul 23, 2026
Base automatically changed from feat/chat-notification-avatars to code/cash July 23, 2026 21:36
@bmc08gt
bmc08gt merged commit c46c130 into code/cash Jul 23, 2026
2 of 3 checks passed
@bmc08gt
bmc08gt deleted the feat/tipping branch July 23, 2026 21:37
bmc08gt added a commit that referenced this pull request Jul 24, 2026
* feat(chat): show avatars for chat and push notifications

Surface counterparty avatars in chat notifications and rows:

- NotificationService loads the sender's remote avatar via Coil and
  falls back to the profile display name / social handle for TIP_DM
  senders (no device contact exists for them).
- Add displayName + image to ConversationReference so chat rows can
  render name and avatar.
- ContactAvatar crops (ContentScale.Crop) to avoid letterboxing.
- MediaItem.rendition()/url() default the preferred rendition to
  ORIGINAL, making the argument optional.

* feat(tipping): send a tip to a scanned user's tip card

Adds the end-to-end tipping flow: scan (or deeplink) another user's tip
card, choose an amount, and send them a tip that opens the resulting DM
chat.

- TippingCoordinator (shared/tipping): resolves the recipient's tip
  card, holds the tip selection (amount + token + send state), derives
  region-aware presets and min/max (send limit ∩ balance) amounts,
  enforces the send limit, and runs the transfer via TransactionController.
- Scanner: ScannableDecorator dispatch (Payable/TipCard), TipUserModal
  (presets, token, slide-to-confirm), affordability gating, and a
  post-tip handoff into the tipped user's chat with the tips list beneath.
- Custom tip-amount entry (features/tipping) with region/currency change
  and below-min / over-balance gating (add-money prompt on insufficient).
- Session/nav wiring: TipCardDelegate, /tip/{userId} deeplink, routes,
  and MainActivity LocalTipCoordinator provision.
- Tip-card sharing via the share sheet; token-selection wired for Tip.
bmc08gt added a commit that referenced this pull request Jul 24, 2026
On cold launch, MainRoot.buildNavGraphForLaunch bundles a tip-card
deeplink into pendingAction (alongside OpenCashLink and Login) and
MainRoot fires it eagerly via App.kt's onPendingAction callback. But
that callback only handled OpenCashLink and Login — PresentTipCard fell
into the no-op `else` branch and was dropped, and the subsequent
`deepLink = null` erased the link before the fallback
LaunchedEffect(deepLink, currentRoute) could recover it. The tip card
was silently lost on every cold start.

Warm launches were unaffected because the app is already past Loading,
so the fallback effect (which does handle PresentTipCard) processes the
link directly.

Add the missing PresentTipCard branch to onPendingAction so it calls
session.resolveTipCard(userId) eagerly, mirroring the cash-link path.

The gap was introduced in c46c130 (#1127), which wired PresentTipCard
into buildNavGraphForLaunch and the fallback effect but not the eager
onPendingAction dispatcher.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: build-system Gradle, convention plugins, build-logic area: deeplinks Deep link handling, URL routing, and link parsing area: payments Payments, transfers, intents, billing area: scanner QR/Kikcode scanning, camera area: session area: tokens Token accounts, balances, token info area: ui Compose UI, theme, components, resources type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant