feat(identity): which profile opens, on launch and after a switch

Phase 3 of docs/multiple-profiles.md. The startup screen learns to agree with
the switch.

The table that picks what to open is lifted out of the screen's remember into
StartupChoice.resolve, where it can be read and tested, because its order was
the whole decision and it was wrong in the one way a switch would hit:
"!startWalletImmediately -> null" sat above "desiredWalletId != null", and
nothing ever set the flag back to true. So after the first visit to the
selector, every sign-in on that device landed on the selector instead of the
profile it had just signed in. Two rows move: what a switch or a sign-in
named goes above the user's earlier "show me the list", since it is the more
specific instruction; and the single-identity row drops below it, since when
both are set they name the same thing.

The default is written. GlobalPrefs.getDefaultWallet has been read by startup
since Phoenix and saved by nothing in this app, so a cold boot with two
profiles was the selector every time with no memory of which one was open.
setActiveIdentity now saves the id it activates -- every activation goes
through it, startup for all three kinds and the two tails through startup --
so the default is always the profile most recently open. The two forget tails
clear it, since the default is the one memory of an identity that would
otherwise outlive it. Both writes are wrapped: a default that could not be
recorded is a selector on the next boot, not a crash now. The screen reads
the saved value as a default only when it names a wallet, which is the one
thing left to decide at the call site.

The startup screen's literals go to the catalogue, and "wallet" goes with
them except in the one place a wallet is what is starting: "Starting wallet"
is shown from StartupViewState.StartingBusiness, which only the branch with
a wallet attached reaches, and stays. The rest become "Preparing profiles",
"Opening profile", "Decrypting", "Loading preferences", "Unlock to continue"
and "Could not load the profiles on this device"; the selector's title is
"Choose a profile", and select_a_wallet goes.

Tests: StartupChoiceTest in commonTest, one case per row and the two
orderings this phase is for -- a desired id opens even after the user once
asked for the list, and one identity with the list asked for still shows it.
IdentitySwitchJvmTest gains the cold boot: activate A then B, and a fresh
view model over the same directory resolves B without asking; forget the
default, and it resolves nothing. Found on the way and recorded in the test:
DataStoreManager caches the global preferences once per process, bound to
whichever directory was current when the first test in the JVM asked -- the
same trap the nsec plan recorded for user preferences -- so the test reads
the default through the view model's own instance rather than one of its
own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pulled-From: curated/curated@00fc996995
This commit is contained in:
Kgothatso Ngako
2026-09-13 00:43:21 +02:00
parent 84ac84ccaf
commit 73a0e5b9c2
7 changed files with 233 additions and 22 deletions

View File

@@ -209,7 +209,6 @@
<string name="search_member_functionality">Search member functionality</string>
<string name="search_message_functionality_will_be_here">Search message functionality will be here.</string>
<string name="see_how_deep_the_rabbit_hole_goes">See how deep the rabbit hole goes</string>
<string name="select_a_wallet">Select a wallet</string>
<string name="send_message">Send message</string>
<string name="share_profile">Share profile</string>
<string name="shared_key">Shared key</string>
@@ -470,4 +469,13 @@
<string name="you_said_you_stored_it">You said you stored it</string>
<!-- The bar on the note composer, which had no bar before it had a back button. -->
<string name="new_note">New note</string>
<!-- Several profiles on a device, docs/multiple-profiles.md. The startup screen's literals,
with "wallet" kept only where a wallet is what is starting. -->
<string name="choose_a_profile">Choose a profile</string>
<string name="could_not_load_the_profiles_on_this_device">Could not load the profiles on this device</string>
<string name="decrypting">Decrypting…</string>
<string name="opening_profile">Opening profile…</string>
<string name="preparing_profiles">Preparing profiles…</string>
<string name="starting_wallet">Starting wallet…</string>
<string name="unlock_to_continue">Unlock to continue</string>
</resources>