fix: route your own tip card to the You tab (deeplink + scan) - #1317
Merged
Conversation
A `/tip/{self}` deeplink dead-ended: AppRouter always produced
PresentTipCard, and the self-check lived downstream in TipCardDelegate as
a bare `return` — so tapping your own tip card link did nothing at all.
Decide it in the router instead. A self-targeted tip card link now
resolves to Navigate(Sheets.Menu) — the You tab, which owns your tip card
(NavBarRoutes: NavBarButton.TipCard -> Sheets.Menu). Every existing
dispatch site already handles Navigate: cold start goes through
buildNavGraphForLaunch, which replaces the launch home with a tab-home
deeplink route, and the warm path goes through navigateAll, which wraps
it as a sheet under v1 and swaps the tab under v2.
The TipCardDelegate guard stays — scanning your own QR still reaches it —
but its comment no longer claims the self case never comes through.
Scanning your own tip code is unchanged and still no-ops.
Scanning your own tip card had the same dead end the deeplink did: the guard in TipCardDelegate.resolveTipCard returned bare, so the scan produced no visible outcome at all. Both scan shapes — a QR tip link (Scanner hands the id straight to resolveTipCard) and an OpenCode tip payload (CodeScanDelegate raises TipCardScanned, which the shell routes to the same call) — funnel through that one guard, so it's the place that has to answer for them. It now raises TipCardEvent.OwnCardScanned on a new UI-facing flow instead of returning silently, and the scanner collects it and navigates to Sheets.Menu — the same You tab the deeplink lands on. tipCardEvents is separate from TipCardDelegate.events: that channel is the shell's single consumer, this one is the UI's. It's replay-less, so an event raised with no scanner on screen is dropped, which is right — every producer runs while the scanner is composed. TipCardOperations is only implemented by TipCardDelegate, and RealSessionController delegates to it, so the new member propagates without touching the shell.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Hitting your own Tip Card did nothing at all — via a
/tip/{self}deeplink, or by scanning your own code.Tipping yourself is a payment no-op, so the flow was correctly disabled — but it was disabled by a bare
returninTipCardDelegate.resolveTipCard, after the deeplink or scan had already been consumed. The user is left on whatever screen they were on with no feedback that anything happened.Both now land on the You tab —
AppRoute.Sheets.Menu, the surface that owns your tip card (NavBarRoutes:NavBarButton.TipCard -> Sheets.Menu).Deeplink
Decided in
AppRouter, which gains acurrentUserIdProviderwired inRouterModulefrom theUserManagerit already injects. A self-targeted link resolves toDeeplinkAction.Navigate(listOf(AppRoute.Sheets.Menu))rather thanPresentTipCard.Routing it as a plain
Navigatemeans every existing dispatch site handles it unchanged:Navigatebranch inMainRoot, wherebuildNavGraphForLaunchalready replaces the launch home with a tab-home deeplink route (you get[Sheets.Menu], not Menu stacked on Wallet).codeNavigator.navigateAll(...)inApp.kt, which wraps it as a sheet under v1 and swaps the tab under v2.Sheets.Menuis already emitted by the router for the my-account email-verification link, so both UI versions are known to handle it.Scan
Two scan shapes reach this: a QR tip link (
Scannerhands the id straight toresolveTipCard) and an OpenCode tip payload (CodeScanDelegateraisesTipCardScanned, which the shell routes to the same call). Both funnel through the one guard inTipCardDelegate, so that is where it is answered — it raisesTipCardEvent.OwnCardScannedon a new UI-facing flow instead of returning silently, andScannercollects it and navigates.tipCardEventsis deliberately separate fromTipCardDelegate.events: that channel is the shell's single consumer (consumeAsFlow), this one is the UI's. It is replay-less, so an event raised with no scanner on screen is dropped — correct here, since every producer runs while the scanner is composed.TipCardOperationsis only implemented byTipCardDelegateandRealSessionControllerdelegates to it, so the new member propagates without touching the shell.Tests
AppRouterTest— self link resolves toNavigate([Sheets.Menu]); another user toPresentTipCard; a nullaccountIdtoPresentTipCard, so a link opened before the account resolves is not swallowed.TipCardDelegateTest(new) — own id raisesOwnCardScannedand never calls the coordinator; another id resolves and presents as before.