diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 6fd951d95a..62507b79fb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -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) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 269e4ed12e..8e0703715c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -76,7 +76,7 @@ class MainActivity : AppCompatActivity() { val accountStateViewModel: AccountStateViewModel = viewModel() LaunchedEffect(key1 = Unit) { - accountStateViewModel.tryLoginExistingAccountAsync() + accountStateViewModel.loginWithDefaultAccountIfLoggedOff() } AccountScreen(accountStateViewModel, sharedPreferencesViewModel) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index 89fefa6780..bcc6cc9f90 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -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)) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index d471791146..cbaecf3f0e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -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) } } }