Skip to content

feat(router): open a person's flipcash.com link on their profile - #1608

Merged
bmc08gt merged 7 commits into
code/cashfrom
feat/profile-deeplink
Sep 28, 2026
Merged

bmc08gt merged 7 commits into
code/cashfrom
feat/profile-deeplink

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

A tapped flipcash.com/<username> or flipcash.com/<uuid> presented that user's tip card, and TipCardDecorator then pushed their DM after 450ms. It now opens their profile over the Chats tab. The profile's Message button opens the DM through the same dmRoute() the chat profile uses. iOS is making the same change separately by pushing its UserProfileScreen.

What changed

  • Classification. AppRouter.handleProfileLink() returns DeeplinkType.Profile(ProfileAddress), which replaces TipcardByUsername and also covers the bare-host UUID form. /tip/<uuid> is still Tipcard and still presents the card.
  • Dispatch. Profile produces DeeplinkAction.Navigate([Tabs.Chats, Messaging.Profile(address)]). App.kt and MainRoot already handle Navigate on warm and cold start, so neither needed a new branch.
  • Screen. New top-level AppRoute.Messaging.Profile. ProfileScreen renders the same screen as a chat's profile: ChatProfileScreen splits into its chat wrapper and PersonProfileScreen, which takes the chat as nullable. With no chat behind it there is no Mute row or muted chip, and Report and Block stay. ProfileViewModel resolves the address through ProfileController, then hands the person to ChatProfileViewModel, which runs Block; a successful block pops the profile. dmRoute() moved into ProfileShortcuts.kt.
  • Scanner. A scanned profile link still presents the tip card, because a printed code is there to be paid.
  • Link cards in chat classify both forms as LinkCard.User, as before. Tapping another person’s card now pushes their profile instead of the DM. Your own card and a card for the person you’re already talking to behave as before.
  • Share. Every person's profile has a Share shortcut: a DM's counterpart, a group member, your own, and one a link opened. It shares their flipcash.com link through Shareable.TipCard, in the handle form when there is one, via rememberProfileShare(). Message and Send Cash keep profileShortcutRecipient's rule.
  • Join date. ChatProfileViewModel.Event.OnParticipantSet takes fromServer, so a linked profile uses the join date its lookup already fetched instead of fetching the profile again.

Own link and failures

  • Own link. Your own link still lands on the You tab. The router can't match a handle until your profile has loaded, so on a cold start the screen catches it instead: when the lookup returns your id, it sends you to the You tab.
  • Failures use the tip-card path's messages. An unclaimed handle shows the "Nobody has claimed @x" info bar. A failed fetch, an unknown id, or a profile with no id shows "Couldn't Open Profile" (a new string with the tip card's wording). In each case the screen pops.

Tests

  • AppRouterTest: the bare-host tests now expect Profile and the new Navigate stack. A new test pins /tip/<uuid> to PresentTipCard.
  • New ProfileViewModelTest (7 cases): resolve by handle and by id, unclaimed handle, failed fetch, unknown id, a profile with no id, and your own handle.
  • LinkCardClassifierTest, ConversionsTest and DeeplinkScanPolicyTest are updated for the renamed type.

A tapped `flipcash.com/<username>` or `flipcash.com/<uuid>` used to present
that user's tip card, and TipCardDecorator then pushed their DM 450ms later.
It now opens their profile, over the Chats tab, with a Message shortcut into
the same DM route the chat profile uses.

- `DeeplinkType.TipcardByUsername` becomes `DeeplinkType.Profile`, which
  also takes the bare-host UUID form. `/tip/<uuid>` stays `Tipcard` and
  still presents the card.
- New `AppRoute.Messaging.Profile(ProfileAddress)` and `ProfileScreen`,
  reusing `ProfileHeader`, `ProfileShortcuts` and `dmRoute()`.
  `ProfileViewModel` resolves the handle or id.
- A scanned profile link still presents the tip card: a printed code is
  there to be paid.
- Your own link still lands on the You tab. A cold-start self-link by
  handle, which the router can't match yet, is caught by the screen once
  the lookup returns your id.
- An unclaimed handle shows "Nobody has claimed @x" and a failed lookup
  shows "Couldn't Open Profile"; either pops the screen.
@bmc08gt bmc08gt self-assigned this Sep 28, 2026
@github-actions github-actions Bot added type: feature New functionality area: scanner QR/Kikcode scanning, camera area: deeplinks Deep link handling, URL routing, and link parsing and removed type: feature New functionality labels Sep 28, 2026
Tapping another person's link card in a chat pushed the DM with them.
It now pushes their profile, the screen their flipcash.com link opens,
and its Message shortcut goes on to the DM. Your own card and a card for
the person you're already talking to behave as before.
The profile a link opens gets a Share shortcut next to Message. It shares
the same flipcash.com link through Shareable.TipCard, in the handle form
when they have one, titled with their name.

The chat profile keeps just Message: ProfileShortcuts takes Share as an
optional callback and only the standalone screen passes it.
@github-actions github-actions Bot added the type: feature New functionality label Sep 28, 2026
Tapping a member's avatar in a group opens the in-chat profile, which
already shows Message for them. It now shows Share too, with the same
link and title as the profile a link opens. A DM's profile still has no
shortcuts.

The share handler moves into rememberProfileShare() so both screens
build the Shareable the same way.
The profile a flipcash.com link opens had its own layout with only the
Message and Share shortcuts. It now renders the same screen as a chat's
profile, so it has Report and Block, and its rows follow the rules that
screen already has.

ChatProfileScreen splits into the chat wrapper and PersonProfileScreen,
which takes the chat as nullable. With no chat there is no Mute row or
muted chip, and the shortcuts show. ProfileViewModel still does the
lookup, then hands the person to ChatProfileViewModel, which runs Block.
A successful block pops the profile, since there is no chat to leave.
ChatProfileViewModel fetches the person's profile again to get a join
date the chat's cached copy lacks. A profile a link opened was fetched a
moment earlier, so that second request was redundant. OnParticipantSet
now takes fromServer, and ProfileScreen sets it to use the join date it
already has.
Share followed Message's rule, so a tip DM's profile and your own had
none. It now shows for any person with a link: the DM's counterpart,
a group member, yourself, and a profile a link opened. Message and Send
Cash keep profileShortcutRecipient's rule, so ProfileShortcuts takes
onMessage as nullable.
@bmc08gt
bmc08gt merged commit 587463d into code/cash Sep 28, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the feat/profile-deeplink branch September 28, 2026 22:14
bmc08gt added a commit that referenced this pull request Sep 28, 2026
#1608 split ChatProfileScreen into PersonProfileScreen, which leaves out
Mute and shows Message when no chat is behind it. A mention's profile now
passes no chat instead of carrying its own ProfileOrigin rule, and the
mention dialogs use the strings #1608 added for the same cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: deeplinks Deep link handling, URL routing, and link parsing area: scanner QR/Kikcode scanning, camera type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant