Phase 4 of docs/multiple-profiles.md. One pushed screen, and the startup
selector brought up to match it.
ProfilesRoute, reached from the profile tab's row -- "Switch profile", where
it said "Change account" and went to the pending screen -- and drawn by
ProfilesScreen: a top app bar with a back button, and WalletsSelector as its
whole content with the open profile above the divider and the others below.
Tapping another row is switchToIdentity and nothing else; the observer
restarts the app as that identity through its lock gate, so the screen is
never around to see the result. Tapping the open row does nothing. Three
states, said so: loading while the list is read, which in practice is never
seen; an unreadable key file, through ErrorState with a retry that re-lists;
and the list. Empty cannot happen while something is signed in and the screen
does not pretend it can. One column at every width. The row is offered to
every kind: a read-only identity can leave for another profile the same way
a signing one can.
ProfilesViewModel joins the flows the app already holds -- the listing state,
the identities, the active identity, the wallet metadata -- to the profile
rows for the listed keys, through NostrRepository.observeProfilesOf, one map
that moves when any of them does. Nothing in it writes.
What a row shows changes. WalletsSelector showed "Default name" over a random
emoji for every row, because nothing in this app writes the wallet metadata's
name, and two profiles side by side both called Default name and told apart
by a bech32 string is not a switcher. The row now takes the nostr profile --
humanReadableNameOrPubkey over ProfileAvatar, the widgets the profile tab
draws itself with -- with the npub on the second line, and falls back to the
npub over the metadata's emoji for a key the device has no kind 0 for yet:
one just created, or a read-only one that was never found. And it says what
the device holds for the profile before the tap: "Wallet" for a seed
attached, beside the "Read only" that was already there, and nothing for the
plain case of a bare key. It is the difference between a profile that can be
signed out of and one whose sign-out is a wallet question, and between two
profiles with the same name. The startup screen draws the same widget and
gets the same map through rememberProfilesOf, so both lists look the same.
The selector's dead globalPrefs parameter goes with the rewrite.
Tests: ProfilesScreenJvmTest, on the unmerged tree, with a wallet-attached A
open, a bare B and a read-only C -- A by its nostr name with its npub and
"Wallet" under it, B and C by their npub with only C labelled, no "Default
name" anywhere, the open one drawn above the others; tapping A calls
nothing and tapping B calls the switch once with B's id; an unreadable key
file is an error whose retry is counted; the bar has a back button.
ReadOnlyEntrancesJvmTest asserts "Switch profile" for both kinds.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pulled-From: curated/curated@25464595f4