fix(multi-account): npub-only login stores ViewOnly type, reactive display names

Root cause of npub-only switch failure:
loginWithKey() with pubkey created AccountState with signerType=Internal
(default). switchAccount then called loadInternalAccount which requires
a private key from SecureKeyStorage → failed. Now sets ViewOnly.

Display names not showing:
- resolveDisplayName() ran at composition time but metadata hadn't
  loaded from relays yet. Dropdown never recomposed when it arrived.
- Added metadataVersion counter to DesktopLocalCache, incremented on
  each consumeMetadata(). Dropdown collects it to trigger recomposition
  when user names become available.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
nrobi144
2026-04-29 09:48:16 +03:00
parent 29aa1d6c9c
commit 1032db0c05
3 changed files with 11 additions and 0 deletions
@@ -536,6 +536,7 @@ class AccountManager internal constructor(
npub = keyPair.pubKey.toNpub(),
nsec = null,
isReadOnly = true,
signerType = SignerType.ViewOnly,
)
_accountState.value = state
Result.success(state)
@@ -78,6 +78,10 @@ class DesktopLocalCache : ICacheProvider {
private val _followedUsers = MutableStateFlow<Set<HexKey>>(emptySet())
val followedUsers: StateFlow<Set<HexKey>> = _followedUsers.asStateFlow()
/** Increments on each metadata update — observe to recompose when user names change. */
private val _metadataVersion = MutableStateFlow(0L)
val metadataVersion: StateFlow<Long> = _metadataVersion.asStateFlow()
companion object {
}
@@ -151,6 +155,7 @@ class DesktopLocalCache : ICacheProvider {
val newUserMetadata = event.contactMetaData()
if (newUserMetadata != null) {
user.updateUserInfo(newUserMetadata, event)
_metadataVersion.value++
// Invalidate metadata flows on notes by this author that have observers
// so QuotedNoteEmbed/FeedNoteCard recompose with updated avatar/name
notes.forEach { _, note ->
@@ -43,6 +43,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -95,6 +96,10 @@ fun AccountSwitcherDropdown(
var expanded by remember { mutableStateOf(false) }
var confirmLogoutNpub by remember { mutableStateOf<String?>(null) }
// Observe metadata version to recompose when user display names load from relays
@Suppress("UNUSED_VARIABLE")
val metadataVersion by localCache?.metadataVersion?.collectAsState() ?: remember { mutableStateOf(0L) }
Box(modifier = modifier) {
IconButton(
onClick = { expanded = true },