Add account, switch account, and logout flows

This commit is contained in:
maxmoney21m 2023-03-12 02:42:50 +08:00
parent 9561261bf4
commit b40bde10a0
3 changed files with 116 additions and 35 deletions

View File

@ -80,18 +80,27 @@ object LocalPreferences {
} }
} }
fun clearEncryptedStorage(npub: String? = null) { fun clearEncryptedStorage(npub: String) {
val encPrefs = encryptedPreferences(npub) val userPrefs = encryptedPreferences(npub)
encPrefs.edit().apply { userPrefs.edit().clear().apply()
encPrefs.all.keys.forEach { removeAccount(npub)
remove(it)
if (savedAccounts.isEmpty()) {
val appPrefs = encryptedPreferences()
appPrefs.edit().clear().apply()
} else if (currentAccount == npub) {
currentAccount = savedAccounts.elementAt(0)
} }
// encPrefs.edit().apply {
// encPrefs.all.keys.forEach {
// remove(it)
// }
// encryptedPreferences.all.keys.filter { // encryptedPreferences.all.keys.filter {
// it.startsWith(npub) // it.startsWith(npub)
// }.forEach { // }.forEach {
// remove(it) // remove(it)
// } // }
}.apply() // }.apply()
} }
fun findAllLocalAccounts(): List<AccountInfo> { fun findAllLocalAccounts(): List<AccountInfo> {
@ -132,6 +141,11 @@ object LocalPreferences {
}.apply() }.apply()
} }
fun login(account: Account) {
setCurrentAccount(account)
saveToEncryptedStorage(account)
}
fun loadFromEncryptedStorage(): Account? { fun loadFromEncryptedStorage(): Account? {
encryptedPreferences(currentAccount).apply { encryptedPreferences(currentAccount).apply {
val pubKey = getString(PrefKeys.NOSTR_PUBKEY, null) ?: return null val pubKey = getString(PrefKeys.NOSTR_PUBKEY, null) ?: return null

View File

@ -1,6 +1,7 @@
package com.vitorpamplona.amethyst.ui.navigation package com.vitorpamplona.amethyst.ui.navigation
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -12,8 +13,12 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.IconButton import androidx.compose.material.IconButton
@ -48,13 +53,18 @@ import androidx.compose.ui.platform.LocalAutofill
import androidx.compose.ui.platform.LocalAutofillTree import androidx.compose.ui.platform.LocalAutofillTree
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.LocalPreferences
@ -103,6 +113,11 @@ fun AccountSwitchBottomSheet(
.fillMaxWidth() .fillMaxWidth()
.padding(32.dp, 16.dp), .padding(32.dp, 16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) {
Row(
modifier = Modifier.clickable {
accountStateViewModel.login(acc.npub)
}
) { ) {
AsyncImageProxy( AsyncImageProxy(
model = ResizeImage(acc.profilePicture, 64.dp), model = ResizeImage(acc.profilePicture, 64.dp),
@ -127,7 +142,11 @@ fun AccountSwitchBottomSheet(
Text("") Text("")
} }
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = { /*TODO*/ }) { }
IconButton(
onClick = { accountStateViewModel.logOff(acc.npub) }
) {
Icon(imageVector = Icons.Default.Logout, "Logout") Icon(imageVector = Icons.Default.Logout, "Logout")
} }
} }
@ -229,6 +248,49 @@ fun AccountSwitchBottomSheet(
style = MaterialTheme.typography.caption style = MaterialTheme.typography.caption
) )
} }
Spacer(modifier = Modifier.height(16.dp))
Button(
onClick = {
if (key.value.text.isBlank()) {
errorMessage = context.getString(R.string.key_is_required)
}
try {
accountStateViewModel.login(key.value.text)
} catch (e: Exception) {
errorMessage = context.getString(R.string.invalid_key)
}
},
shape = RoundedCornerShape(35.dp),
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
colors = ButtonDefaults
.buttonColors(
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = stringResource(R.string.login))
}
Spacer(modifier = Modifier.height(16.dp))
ClickableText(
text = AnnotatedString(stringResource(R.string.generate_a_new_key)),
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
onClick = {
accountStateViewModel.newKey()
},
style = TextStyle(
fontSize = 14.sp,
textDecoration = TextDecoration.Underline,
color = MaterialTheme.colors.primary,
textAlign = TextAlign.Center
)
)
} }
} }
} }

View File

@ -26,10 +26,14 @@ class AccountStateViewModel() : ViewModel() {
// Keeps it in the the UI thread to void blinking the login page. // Keeps it in the the UI thread to void blinking the login page.
// viewModelScope.launch(Dispatchers.IO) { // viewModelScope.launch(Dispatchers.IO) {
tryLoginExistingAccount()
// }
}
private fun tryLoginExistingAccount() {
LocalPreferences.loadFromEncryptedStorage()?.let { LocalPreferences.loadFromEncryptedStorage()?.let {
login(it) login(it)
} }
// }
} }
fun login(key: String) { fun login(key: String) {
@ -47,18 +51,18 @@ class AccountStateViewModel() : ViewModel() {
Account(Persona(Hex.decode(key))) Account(Persona(Hex.decode(key)))
} }
LocalPreferences.saveToEncryptedStorage(account) LocalPreferences.login(account)
login(account) login(account)
} }
fun newKey() { fun newKey() {
val account = Account(Persona()) val account = Account(Persona())
LocalPreferences.saveToEncryptedStorage(account) LocalPreferences.login(account)
login(account) login(account)
} }
fun login(account: Account) { fun login(account: Account) {
LocalPreferences.setCurrentAccount(account) LocalPreferences.login(account)
if (account.loggedIn.privKey != null) { if (account.loggedIn.privKey != null) {
_accountContent.update { AccountState.LoggedIn(account) } _accountContent.update { AccountState.LoggedIn(account) }
@ -82,7 +86,7 @@ class AccountStateViewModel() : ViewModel() {
} }
} }
fun logOff() { fun logOff(npub: String) {
val state = accountContent.value val state = accountContent.value
when (state) { when (state) {
@ -101,6 +105,7 @@ class AccountStateViewModel() : ViewModel() {
_accountContent.update { AccountState.LoggedOff } _accountContent.update { AccountState.LoggedOff }
LocalPreferences.clearEncryptedStorage() LocalPreferences.clearEncryptedStorage(npub)
tryLoginExistingAccount()
} }
} }