From 1032db0c05f93daf0dc1f4371bdaeaa55100a81c Mon Sep 17 00:00:00 2001 From: nrobi144 Date: Wed, 29 Apr 2026 09:48:16 +0300 Subject: [PATCH] fix(multi-account): npub-only login stores ViewOnly type, reactive display names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../vitorpamplona/amethyst/desktop/account/AccountManager.kt | 1 + .../amethyst/desktop/cache/DesktopLocalCache.kt | 5 +++++ .../amethyst/desktop/ui/account/AccountSwitcherDropdown.kt | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt index a97c831b2..17626a82e 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/account/AccountManager.kt @@ -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) diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt index 08b57e10e..87128a75b 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/cache/DesktopLocalCache.kt @@ -78,6 +78,10 @@ class DesktopLocalCache : ICacheProvider { private val _followedUsers = MutableStateFlow>(emptySet()) val followedUsers: StateFlow> = _followedUsers.asStateFlow() + /** Increments on each metadata update — observe to recompose when user names change. */ + private val _metadataVersion = MutableStateFlow(0L) + val metadataVersion: StateFlow = _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 -> diff --git a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/account/AccountSwitcherDropdown.kt b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/account/AccountSwitcherDropdown.kt index dabb3097c..2aace03a2 100644 --- a/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/account/AccountSwitcherDropdown.kt +++ b/desktopApp/src/jvmMain/kotlin/com/vitorpamplona/amethyst/desktop/ui/account/AccountSwitcherDropdown.kt @@ -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(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 },