Correctly logs off from the current account when creating new accounts from inside an existing account.

This commit is contained in:
Vitor Pamplona
2025-07-31 17:45:21 -04:00
parent 14e860928b
commit fe8f519dbf
4 changed files with 58 additions and 47 deletions

View File

@@ -270,7 +270,7 @@ object LocalPreferences {
* deleted
*/
@SuppressLint("ApplySharedPref")
suspend fun updatePrefsForLogout(accountInfo: AccountInfo) {
suspend fun deleteAccount(accountInfo: AccountInfo) {
Log.d("LocalPreferences", "Saving to encrypted storage updatePrefsForLogout ${accountInfo.npub}")
withContext(Dispatchers.IO) {
encryptedPreferences(accountInfo.npub).edit(commit = true) { clear() }
@@ -285,7 +285,7 @@ object LocalPreferences {
}
}
suspend fun updatePrefsForLogin(accountSettings: AccountSettings) {
suspend fun setDefaultAccount(accountSettings: AccountSettings) {
setCurrentAccount(accountSettings)
saveToEncryptedStorage(accountSettings)
}

View File

@@ -76,7 +76,7 @@ class MainActivity : AppCompatActivity() {
val accountStateViewModel: AccountStateViewModel = viewModel()
LaunchedEffect(key1 = Unit) {
accountStateViewModel.tryLoginExistingAccountAsync()
accountStateViewModel.loginWithDefaultAccountIfLoggedOff()
}
AccountScreen(accountStateViewModel, sharedPreferencesViewModel)

View File

@@ -297,8 +297,8 @@ private fun NavigateIfIntentRequested(
if (actionableNextPage != null) {
actionableNextPage?.let { nextRoute ->
val npub = runCatching { URI(intentNextPage.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
if (npub != null && accountStateViewModel.currentAccount() != npub) {
accountStateViewModel.switchUserSync(npub, nextRoute)
if (npub != null && accountStateViewModel.currentAccountNPub() != npub) {
accountStateViewModel.checkAndSwitchUserSync(npub, nextRoute)
} else {
val currentRoute = getRouteWithArguments(nav.controller)
if (!isSameRoute(currentRoute, nextRoute)) {
@@ -353,8 +353,8 @@ private fun NavigateIfIntentRequested(
if (newPage != null) {
scope.launch {
val npub = runCatching { URI(uri.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
if (npub != null && accountStateViewModel.currentAccount() != npub) {
accountStateViewModel.switchUserSync(npub, newPage)
if (npub != null && accountStateViewModel.currentAccountNPub() != npub) {
accountStateViewModel.checkAndSwitchUserSync(npub, newPage)
} else {
val currentRoute = getRouteWithArguments(nav.controller)
if (!isSameRoute(currentRoute, newPage)) {

View File

@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.model.DefaultDMRelayList
import com.vitorpamplona.amethyst.model.DefaultNIP65List
import com.vitorpamplona.amethyst.model.DefaultNIP65RelaySet
import com.vitorpamplona.amethyst.model.DefaultSearchRelayList
import com.vitorpamplona.amethyst.model.preferences.AccountPreferenceStores.Companion.torSettings
import com.vitorpamplona.amethyst.service.Nip05NostrAddressVerifier
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.tor.TorSettings
@@ -51,6 +52,7 @@ import com.vitorpamplona.quartz.nip19Bech32.bech32.bechToBytes
import com.vitorpamplona.quartz.nip19Bech32.entities.NAddress
import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
import com.vitorpamplona.quartz.nip19Bech32.entities.NNote
import com.vitorpamplona.quartz.nip19Bech32.entities.NProfile
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
import com.vitorpamplona.quartz.nip19Bech32.entities.NRelay
@@ -85,16 +87,16 @@ class AccountStateViewModel : ViewModel() {
private var collectorJob: Job? = null
fun tryLoginExistingAccountAsync() {
fun loginWithDefaultAccountIfLoggedOff() {
// pulls account from storage.
if (_accountContent.value !is AccountState.LoggedIn) {
viewModelScope.launch {
tryLoginExistingAccount()
loginWithDefaultAccount()
}
}
}
private suspend fun tryLoginExistingAccount(route: Route? = null) {
private suspend fun loginWithDefaultAccount(route: Route? = null) {
val accountSettings =
withContext(Dispatchers.IO) {
LocalPreferences.loadCurrentAccountFromEncryptedStorage()
@@ -107,9 +109,7 @@ class AccountStateViewModel : ViewModel() {
}
}
private suspend fun requestLoginUI() {
_accountContent.update { AccountState.LoggedOff }
}
private suspend fun requestLoginUI() = _accountContent.update { AccountState.LoggedOff }
suspend fun loginAndStartUI(
key: String,
@@ -124,7 +124,7 @@ class AccountStateViewModel : ViewModel() {
is NSec -> null
is NPub -> parsed.hex.hexToByteArray()
is NProfile -> parsed.hex.hexToByteArray()
is com.vitorpamplona.quartz.nip19Bech32.entities.NNote -> null
is NNote -> null
is NEvent -> null
is NEmbed -> null
is NRelay -> null
@@ -175,7 +175,7 @@ class AccountStateViewModel : ViewModel() {
)
}
LocalPreferences.updatePrefsForLogin(account)
LocalPreferences.setDefaultAccount(account)
startUI(account)
}
@@ -277,6 +277,9 @@ class AccountStateViewModel : ViewModel() {
onError: (String) -> Unit,
) {
try {
if (_accountContent.value is AccountState.LoggedIn) {
prepareLogoutOrSwitch()
}
loginAndStartUI(key, torSettings, transientAccount, loginWithExternalSigner, packageName)
} catch (e: Exception) {
if (e is CancellationException) throw e
@@ -290,31 +293,15 @@ class AccountStateViewModel : ViewModel() {
name: String? = null,
) {
viewModelScope.launch(Dispatchers.IO) {
if (_accountContent.value is AccountState.LoggedIn) {
prepareLogoutOrSwitch()
}
_accountContent.update { AccountState.Loading }
val keyPair = KeyPair()
val tempSigner = NostrSignerSync(keyPair)
val accountSettings = createNewAccount(torSettings, name)
val accountSettings =
AccountSettings(
keyPair = keyPair,
transientAccount = false,
backupUserMetadata = tempSigner.sign(MetadataEvent.newUser(name)),
backupContactList =
ContactListEvent.createFromScratch(
followUsers = listOf(ContactTag(keyPair.pubKey.toHexKey(), null, null)),
relayUse = emptyMap(),
signer = tempSigner,
),
backupNIP65RelayList = AdvertisedRelayListEvent.create(DefaultNIP65List, tempSigner),
backupDMRelayList = ChatMessageRelayListEvent.create(DefaultDMRelayList, tempSigner),
backupSearchRelayList = SearchRelayListEvent.create(DefaultSearchRelayList.toList(), tempSigner),
backupChannelList = ChannelListEvent.create(emptyList(), DefaultChannels, tempSigner),
torSettings = TorSettingsFlow.build(torSettings),
)
// saves to local preferences
LocalPreferences.updatePrefsForLogin(accountSettings)
LocalPreferences.setDefaultAccount(accountSettings)
startUI(accountSettings)
@@ -333,13 +320,38 @@ class AccountStateViewModel : ViewModel() {
}
}
fun createNewAccount(
torSettings: TorSettings,
name: String? = null,
): AccountSettings {
val keyPair = KeyPair()
val tempSigner = NostrSignerSync(keyPair)
return AccountSettings(
keyPair = keyPair,
transientAccount = false,
backupUserMetadata = tempSigner.sign(MetadataEvent.newUser(name)),
backupContactList =
ContactListEvent.createFromScratch(
followUsers = listOf(ContactTag(keyPair.pubKey.toHexKey(), null, null)),
relayUse = emptyMap(),
signer = tempSigner,
),
backupNIP65RelayList = AdvertisedRelayListEvent.create(DefaultNIP65List, tempSigner),
backupDMRelayList = ChatMessageRelayListEvent.create(DefaultDMRelayList, tempSigner),
backupSearchRelayList = SearchRelayListEvent.create(DefaultSearchRelayList.toList(), tempSigner),
backupChannelList = ChannelListEvent.create(emptyList(), DefaultChannels, tempSigner),
torSettings = TorSettingsFlow.build(torSettings),
)
}
fun switchUser(accountInfo: AccountInfo) {
viewModelScope.launch(Dispatchers.IO) {
switchUserSync(accountInfo)
}
}
suspend fun switchUserSync(
suspend fun checkAndSwitchUserSync(
npub: String,
route: Route,
): Boolean {
@@ -353,34 +365,33 @@ class AccountStateViewModel : ViewModel() {
return false
}
suspend fun switchUserSync(
private suspend fun switchUserSync(
accountInfo: AccountInfo,
route: Route? = null,
) {
prepareLogoutOrSwitch()
LocalPreferences.switchToAccount(accountInfo)
tryLoginExistingAccount(route)
loginWithDefaultAccount(route)
}
fun currentAccount() =
fun currentAccountNPub() =
when (val state = _accountContent.value) {
is AccountState.LoggedIn ->
state.accountSettings.keyPair.pubKey
.toNpub()
else -> null
}
fun logOff(accountInfo: AccountInfo) {
viewModelScope.launch(Dispatchers.IO) {
if (accountInfo.npub == currentAccount()) {
if (accountInfo.npub == currentAccountNPub()) {
// log off and relogin with the 0 account
prepareLogoutOrSwitch()
LocalPreferences.updatePrefsForLogout(accountInfo)
tryLoginExistingAccount()
LocalPreferences.deleteAccount(accountInfo)
loginWithDefaultAccount()
} else {
// delete without login off
LocalPreferences.updatePrefsForLogout(accountInfo)
// delete without switching logins
LocalPreferences.deleteAccount(accountInfo)
}
}
}