mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-09-25 21:46:50 +02:00
Correctly logs off from the current account when creating new accounts from inside an existing account.
This commit is contained in:
@@ -270,7 +270,7 @@ object LocalPreferences {
|
|||||||
* deleted
|
* deleted
|
||||||
*/
|
*/
|
||||||
@SuppressLint("ApplySharedPref")
|
@SuppressLint("ApplySharedPref")
|
||||||
suspend fun updatePrefsForLogout(accountInfo: AccountInfo) {
|
suspend fun deleteAccount(accountInfo: AccountInfo) {
|
||||||
Log.d("LocalPreferences", "Saving to encrypted storage updatePrefsForLogout ${accountInfo.npub}")
|
Log.d("LocalPreferences", "Saving to encrypted storage updatePrefsForLogout ${accountInfo.npub}")
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
encryptedPreferences(accountInfo.npub).edit(commit = true) { clear() }
|
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)
|
setCurrentAccount(accountSettings)
|
||||||
saveToEncryptedStorage(accountSettings)
|
saveToEncryptedStorage(accountSettings)
|
||||||
}
|
}
|
||||||
|
@@ -76,7 +76,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val accountStateViewModel: AccountStateViewModel = viewModel()
|
val accountStateViewModel: AccountStateViewModel = viewModel()
|
||||||
|
|
||||||
LaunchedEffect(key1 = Unit) {
|
LaunchedEffect(key1 = Unit) {
|
||||||
accountStateViewModel.tryLoginExistingAccountAsync()
|
accountStateViewModel.loginWithDefaultAccountIfLoggedOff()
|
||||||
}
|
}
|
||||||
|
|
||||||
AccountScreen(accountStateViewModel, sharedPreferencesViewModel)
|
AccountScreen(accountStateViewModel, sharedPreferencesViewModel)
|
||||||
|
@@ -297,8 +297,8 @@ private fun NavigateIfIntentRequested(
|
|||||||
if (actionableNextPage != null) {
|
if (actionableNextPage != null) {
|
||||||
actionableNextPage?.let { nextRoute ->
|
actionableNextPage?.let { nextRoute ->
|
||||||
val npub = runCatching { URI(intentNextPage.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
|
val npub = runCatching { URI(intentNextPage.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
|
||||||
if (npub != null && accountStateViewModel.currentAccount() != npub) {
|
if (npub != null && accountStateViewModel.currentAccountNPub() != npub) {
|
||||||
accountStateViewModel.switchUserSync(npub, nextRoute)
|
accountStateViewModel.checkAndSwitchUserSync(npub, nextRoute)
|
||||||
} else {
|
} else {
|
||||||
val currentRoute = getRouteWithArguments(nav.controller)
|
val currentRoute = getRouteWithArguments(nav.controller)
|
||||||
if (!isSameRoute(currentRoute, nextRoute)) {
|
if (!isSameRoute(currentRoute, nextRoute)) {
|
||||||
@@ -353,8 +353,8 @@ private fun NavigateIfIntentRequested(
|
|||||||
if (newPage != null) {
|
if (newPage != null) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
val npub = runCatching { URI(uri.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
|
val npub = runCatching { URI(uri.removePrefix("nostr:")).findParameterValue("account") }.getOrNull()
|
||||||
if (npub != null && accountStateViewModel.currentAccount() != npub) {
|
if (npub != null && accountStateViewModel.currentAccountNPub() != npub) {
|
||||||
accountStateViewModel.switchUserSync(npub, newPage)
|
accountStateViewModel.checkAndSwitchUserSync(npub, newPage)
|
||||||
} else {
|
} else {
|
||||||
val currentRoute = getRouteWithArguments(nav.controller)
|
val currentRoute = getRouteWithArguments(nav.controller)
|
||||||
if (!isSameRoute(currentRoute, newPage)) {
|
if (!isSameRoute(currentRoute, newPage)) {
|
||||||
|
@@ -33,6 +33,7 @@ import com.vitorpamplona.amethyst.model.DefaultDMRelayList
|
|||||||
import com.vitorpamplona.amethyst.model.DefaultNIP65List
|
import com.vitorpamplona.amethyst.model.DefaultNIP65List
|
||||||
import com.vitorpamplona.amethyst.model.DefaultNIP65RelaySet
|
import com.vitorpamplona.amethyst.model.DefaultNIP65RelaySet
|
||||||
import com.vitorpamplona.amethyst.model.DefaultSearchRelayList
|
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.service.Nip05NostrAddressVerifier
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||||
import com.vitorpamplona.amethyst.ui.tor.TorSettings
|
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.NAddress
|
||||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed
|
import com.vitorpamplona.quartz.nip19Bech32.entities.NEmbed
|
||||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
|
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.NProfile
|
||||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
import com.vitorpamplona.quartz.nip19Bech32.entities.NPub
|
||||||
import com.vitorpamplona.quartz.nip19Bech32.entities.NRelay
|
import com.vitorpamplona.quartz.nip19Bech32.entities.NRelay
|
||||||
@@ -85,16 +87,16 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
|
|
||||||
private var collectorJob: Job? = null
|
private var collectorJob: Job? = null
|
||||||
|
|
||||||
fun tryLoginExistingAccountAsync() {
|
fun loginWithDefaultAccountIfLoggedOff() {
|
||||||
// pulls account from storage.
|
// pulls account from storage.
|
||||||
if (_accountContent.value !is AccountState.LoggedIn) {
|
if (_accountContent.value !is AccountState.LoggedIn) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
tryLoginExistingAccount()
|
loginWithDefaultAccount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun tryLoginExistingAccount(route: Route? = null) {
|
private suspend fun loginWithDefaultAccount(route: Route? = null) {
|
||||||
val accountSettings =
|
val accountSettings =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
LocalPreferences.loadCurrentAccountFromEncryptedStorage()
|
LocalPreferences.loadCurrentAccountFromEncryptedStorage()
|
||||||
@@ -107,9 +109,7 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun requestLoginUI() {
|
private suspend fun requestLoginUI() = _accountContent.update { AccountState.LoggedOff }
|
||||||
_accountContent.update { AccountState.LoggedOff }
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun loginAndStartUI(
|
suspend fun loginAndStartUI(
|
||||||
key: String,
|
key: String,
|
||||||
@@ -124,7 +124,7 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
is NSec -> null
|
is NSec -> null
|
||||||
is NPub -> parsed.hex.hexToByteArray()
|
is NPub -> parsed.hex.hexToByteArray()
|
||||||
is NProfile -> parsed.hex.hexToByteArray()
|
is NProfile -> parsed.hex.hexToByteArray()
|
||||||
is com.vitorpamplona.quartz.nip19Bech32.entities.NNote -> null
|
is NNote -> null
|
||||||
is NEvent -> null
|
is NEvent -> null
|
||||||
is NEmbed -> null
|
is NEmbed -> null
|
||||||
is NRelay -> null
|
is NRelay -> null
|
||||||
@@ -175,7 +175,7 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalPreferences.updatePrefsForLogin(account)
|
LocalPreferences.setDefaultAccount(account)
|
||||||
|
|
||||||
startUI(account)
|
startUI(account)
|
||||||
}
|
}
|
||||||
@@ -277,6 +277,9 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
onError: (String) -> Unit,
|
onError: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
if (_accountContent.value is AccountState.LoggedIn) {
|
||||||
|
prepareLogoutOrSwitch()
|
||||||
|
}
|
||||||
loginAndStartUI(key, torSettings, transientAccount, loginWithExternalSigner, packageName)
|
loginAndStartUI(key, torSettings, transientAccount, loginWithExternalSigner, packageName)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is CancellationException) throw e
|
if (e is CancellationException) throw e
|
||||||
@@ -290,31 +293,15 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
name: String? = null,
|
name: String? = null,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
if (_accountContent.value is AccountState.LoggedIn) {
|
||||||
|
prepareLogoutOrSwitch()
|
||||||
|
}
|
||||||
|
|
||||||
_accountContent.update { AccountState.Loading }
|
_accountContent.update { AccountState.Loading }
|
||||||
|
|
||||||
val keyPair = KeyPair()
|
val accountSettings = createNewAccount(torSettings, name)
|
||||||
val tempSigner = NostrSignerSync(keyPair)
|
|
||||||
|
|
||||||
val accountSettings =
|
LocalPreferences.setDefaultAccount(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)
|
|
||||||
|
|
||||||
startUI(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) {
|
fun switchUser(accountInfo: AccountInfo) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
switchUserSync(accountInfo)
|
switchUserSync(accountInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun switchUserSync(
|
suspend fun checkAndSwitchUserSync(
|
||||||
npub: String,
|
npub: String,
|
||||||
route: Route,
|
route: Route,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -353,34 +365,33 @@ class AccountStateViewModel : ViewModel() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun switchUserSync(
|
private suspend fun switchUserSync(
|
||||||
accountInfo: AccountInfo,
|
accountInfo: AccountInfo,
|
||||||
route: Route? = null,
|
route: Route? = null,
|
||||||
) {
|
) {
|
||||||
prepareLogoutOrSwitch()
|
prepareLogoutOrSwitch()
|
||||||
LocalPreferences.switchToAccount(accountInfo)
|
LocalPreferences.switchToAccount(accountInfo)
|
||||||
tryLoginExistingAccount(route)
|
loginWithDefaultAccount(route)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun currentAccount() =
|
fun currentAccountNPub() =
|
||||||
when (val state = _accountContent.value) {
|
when (val state = _accountContent.value) {
|
||||||
is AccountState.LoggedIn ->
|
is AccountState.LoggedIn ->
|
||||||
state.accountSettings.keyPair.pubKey
|
state.accountSettings.keyPair.pubKey
|
||||||
.toNpub()
|
.toNpub()
|
||||||
|
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logOff(accountInfo: AccountInfo) {
|
fun logOff(accountInfo: AccountInfo) {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
if (accountInfo.npub == currentAccount()) {
|
if (accountInfo.npub == currentAccountNPub()) {
|
||||||
// log off and relogin with the 0 account
|
// log off and relogin with the 0 account
|
||||||
prepareLogoutOrSwitch()
|
prepareLogoutOrSwitch()
|
||||||
LocalPreferences.updatePrefsForLogout(accountInfo)
|
LocalPreferences.deleteAccount(accountInfo)
|
||||||
tryLoginExistingAccount()
|
loginWithDefaultAccount()
|
||||||
} else {
|
} else {
|
||||||
// delete without login off
|
// delete without switching logins
|
||||||
LocalPreferences.updatePrefsForLogout(accountInfo)
|
LocalPreferences.deleteAccount(accountInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user