From 3a2403b3445cbf1006261b8a6bb6c369109ccb4d Mon Sep 17 00:00:00 2001 From: maxmoney21m Date: Sun, 12 Mar 2023 02:18:43 +0800 Subject: [PATCH] Use multiple preference files for different accounts --- .idea/deploymentTargetDropDown.xml | 17 ++ app/src/main/AndroidManifest.xml | 1 + .../com/vitorpamplona/amethyst/Amethyst.kt | 15 ++ .../amethyst/EncryptedStorage.kt | 8 +- .../amethyst/LocalPreferences.kt | 197 ++++++++++-------- .../amethyst/NotificationCache.kt | 4 +- .../vitorpamplona/amethyst/ui/MainActivity.kt | 3 +- .../ui/navigation/AccountSwitchBottomSheet.kt | 132 +++++++++++- .../ui/screen/AccountStateViewModel.kt | 15 +- .../amethyst/ui/screen/loggedIn/MainScreen.kt | 2 +- 10 files changed, 278 insertions(+), 116 deletions(-) create mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/Amethyst.kt diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 000000000..0c0237e9c --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 641da01bb..5a3417398 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ String = { route -> "last_read_route_$route" } +} - private fun prefKeysForAccount(npub: String) = object { - val NOSTR_PRIVKEY = "$npub/nostr_privkey" - val NOSTR_PUBKEY = "$npub/nostr_pubkey" - val DISPLAY_NAME = "$npub/display_name" - val PROFILE_PICTURE_URL = "$npub/profile_picture" - val FOLLOWING_CHANNELS = "$npub/following_channels" - val HIDDEN_USERS = "$npub/hidden_users" - val RELAYS = "$npub/relays" - val DONT_TRANSLATE_FROM = "$npub/dontTranslateFrom" - val LANGUAGE_PREFS = "$npub/languagePreferences" - val TRANSLATE_TO = "$npub/translateTo" - val ZAP_AMOUNTS = "$npub/zapAmounts" - val LATEST_CONTACT_LIST = "$npub/latestContactList" - val HIDE_DELETE_REQUEST_INFO = "$npub/hideDeleteRequestInfo" -// val LAST_READ: (String) -> String = { route -> "$npub/last_read_route_$route" } +private val gson = GsonBuilder().create() + +object LocalPreferences { + private var currentAccount: String? + get() = encryptedPreferences().getString(PrefKeys.CURRENT_ACCOUNT, null) + set(npub) { + val prefs = encryptedPreferences() + prefs.edit().apply { + putString(PrefKeys.CURRENT_ACCOUNT, npub) + }.apply() + } + + private val savedAccounts: Set + get() = encryptedPreferences().getStringSet(PrefKeys.SAVED_ACCOUNTS, null) ?: setOf() + + private fun addAccount(npub: String) { + val accounts = savedAccounts.toMutableSet() + accounts.add(npub) + val prefs = encryptedPreferences() + prefs.edit().apply { + putStringSet(PrefKeys.SAVED_ACCOUNTS, accounts) + }.apply() } - private object PrefKeys { - const val CURRENT_ACCOUNT = "currentlyLoggedInAccount" - -// val NOSTR_PRIVKEY = "nostr_privkey" -// val NOSTR_PUBKEY = "nostr_pubkey" -// val FOLLOWING_CHANNELS = "following_channels" -// val HIDDEN_USERS = "hidden_users" -// val RELAYS = "relays" -// val DONT_TRANSLATE_FROM = "dontTranslateFrom" -// val LANGUAGE_PREFS = "languagePreferences" -// val TRANSLATE_TO = "translateTo" -// val ZAP_AMOUNTS = "zapAmounts" -// val LATEST_CONTACT_LIST = "latestContactList" -// val HIDE_DELETE_REQUEST_INFO = "hideDeleteRequestInfo" - val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } + private fun removeAccount(npub: String) { + val accounts = savedAccounts.toMutableSet() + accounts.remove(npub) + val prefs = encryptedPreferences() + prefs.edit().apply { + putStringSet(PrefKeys.SAVED_ACCOUNTS, accounts) + }.apply() } - private val encryptedPreferences = EncryptedStorage.preferences(context) - private val gson = GsonBuilder().create() + private fun encryptedPreferences(npub: String? = null): SharedPreferences { + return if (DEBUG_PLAINTEXT_PREFERENCES) { + val preferenceFile = if (npub == null) "testing_only" else "testing_only_$npub" + Amethyst.instance.getSharedPreferences(preferenceFile, Context.MODE_PRIVATE) + } else { + return EncryptedStorage.preferences(npub) + } + } - fun clearEncryptedStorage() { - encryptedPreferences.edit().apply { - encryptedPreferences.all.keys.forEach { + fun clearEncryptedStorage(npub: String? = null) { + val encPrefs = encryptedPreferences(npub) + encPrefs.edit().apply { + encPrefs.all.keys.forEach { remove(it) } // encryptedPreferences.all.keys.filter { @@ -69,76 +94,64 @@ class LocalPreferences(context: Context) { } fun findAllLocalAccounts(): List { - encryptedPreferences.apply { - val currentAccount = getString(PrefKeys.CURRENT_ACCOUNT, null) - return encryptedPreferences.all.keys.filter { - it.endsWith("nostr_pubkey") - }.map { - val npub = it.substringBefore("/") - val myPrefs = prefKeysForAccount(npub) - AccountInfo( - npub, - npub == currentAccount, - getString(myPrefs.DISPLAY_NAME, null), - getString(myPrefs.PROFILE_PICTURE_URL, null) - ) - } + return savedAccounts.map { npub -> + val prefs = encryptedPreferences(npub) + + AccountInfo( + npub = npub, + current = npub == currentAccount, + displayName = prefs.getString(PrefKeys.DISPLAY_NAME, null), + profilePicture = prefs.getString(PrefKeys.PROFILE_PICTURE_URL, null) + ) } } - fun saveToEncryptedStorage(account: Account) { - val npub = account.loggedIn.pubKey.toNpub() - val myPrefs = prefKeysForAccount(npub) - - encryptedPreferences.edit().apply { - putString(PrefKeys.CURRENT_ACCOUNT, npub) - account.loggedIn.privKey?.let { putString(myPrefs.NOSTR_PRIVKEY, it.toHex()) } - account.loggedIn.pubKey.let { putString(myPrefs.NOSTR_PUBKEY, it.toHex()) } - putStringSet(myPrefs.FOLLOWING_CHANNELS, account.followingChannels) - putStringSet(myPrefs.HIDDEN_USERS, account.hiddenUsers) - putString(myPrefs.RELAYS, gson.toJson(account.localRelays)) - putStringSet(myPrefs.DONT_TRANSLATE_FROM, account.dontTranslateFrom) - putString(myPrefs.LANGUAGE_PREFS, gson.toJson(account.languagePreferences)) - putString(myPrefs.TRANSLATE_TO, account.translateTo) - putString(myPrefs.ZAP_AMOUNTS, gson.toJson(account.zapAmountChoices)) - putString(myPrefs.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList)) - putBoolean(myPrefs.HIDE_DELETE_REQUEST_INFO, account.hideDeleteRequestInfo) - }.apply() + fun setCurrentAccount(account: Account) { + val npub = account.userProfile().pubkeyNpub() + currentAccount = npub + addAccount(npub) } - fun saveCurrentAccountMetadata(account: Account) { - val myPrefs = prefKeysForAccount(account.loggedIn.pubKey.toNpub()) - - encryptedPreferences.edit().apply { - putString(myPrefs.DISPLAY_NAME, account.userProfile().toBestDisplayName()) - putString(myPrefs.PROFILE_PICTURE_URL, account.userProfile().profilePicture()) + fun saveToEncryptedStorage(account: Account) { + val prefs = encryptedPreferences(account.userProfile().pubkeyNpub()) + prefs.edit().apply { + account.loggedIn.privKey?.let { putString(PrefKeys.NOSTR_PRIVKEY, it.toHex()) } + account.loggedIn.pubKey.let { putString(PrefKeys.NOSTR_PUBKEY, it.toHex()) } + putStringSet(PrefKeys.FOLLOWING_CHANNELS, account.followingChannels) + putStringSet(PrefKeys.HIDDEN_USERS, account.hiddenUsers) + putString(PrefKeys.RELAYS, gson.toJson(account.localRelays)) + putStringSet(PrefKeys.DONT_TRANSLATE_FROM, account.dontTranslateFrom) + putString(PrefKeys.LANGUAGE_PREFS, gson.toJson(account.languagePreferences)) + putString(PrefKeys.TRANSLATE_TO, account.translateTo) + putString(PrefKeys.ZAP_AMOUNTS, gson.toJson(account.zapAmountChoices)) + putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList)) + putBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, account.hideDeleteRequestInfo) + putString(PrefKeys.DISPLAY_NAME, account.userProfile().toBestDisplayName()) + putString(PrefKeys.PROFILE_PICTURE_URL, account.userProfile().profilePicture()) }.apply() } fun loadFromEncryptedStorage(): Account? { - encryptedPreferences.apply { - val npub = getString(PrefKeys.CURRENT_ACCOUNT, null) ?: return null - val myPrefs = prefKeysForAccount(npub) - - val pubKey = getString(myPrefs.NOSTR_PUBKEY, null) ?: return null - val privKey = getString(myPrefs.NOSTR_PRIVKEY, null) - val followingChannels = getStringSet(myPrefs.FOLLOWING_CHANNELS, null) ?: setOf() - val hiddenUsers = getStringSet(myPrefs.HIDDEN_USERS, emptySet()) ?: setOf() + encryptedPreferences(currentAccount).apply { + val pubKey = getString(PrefKeys.NOSTR_PUBKEY, null) ?: return null + val privKey = getString(PrefKeys.NOSTR_PRIVKEY, null) + val followingChannels = getStringSet(PrefKeys.FOLLOWING_CHANNELS, null) ?: setOf() + val hiddenUsers = getStringSet(PrefKeys.HIDDEN_USERS, emptySet()) ?: setOf() val localRelays = gson.fromJson( - getString(myPrefs.RELAYS, "[]"), + getString(PrefKeys.RELAYS, "[]"), object : TypeToken>() {}.type ) ?: setOf() - val dontTranslateFrom = getStringSet(myPrefs.DONT_TRANSLATE_FROM, null) ?: setOf() - val translateTo = getString(myPrefs.TRANSLATE_TO, null) ?: Locale.getDefault().language + val dontTranslateFrom = getStringSet(PrefKeys.DONT_TRANSLATE_FROM, null) ?: setOf() + val translateTo = getString(PrefKeys.TRANSLATE_TO, null) ?: Locale.getDefault().language val zapAmountChoices = gson.fromJson( - getString(myPrefs.ZAP_AMOUNTS, "[]"), + getString(PrefKeys.ZAP_AMOUNTS, "[]"), object : TypeToken>() {}.type ) ?: listOf(500L, 1000L, 5000L) val latestContactList = try { - getString(myPrefs.LATEST_CONTACT_LIST, null)?.let { + getString(PrefKeys.LATEST_CONTACT_LIST, null)?.let { Event.gson.fromJson(it, Event::class.java).getRefinedEvent(true) as ContactListEvent } } catch (e: Throwable) { @@ -147,7 +160,7 @@ class LocalPreferences(context: Context) { } val languagePreferences = try { - getString(myPrefs.LANGUAGE_PREFS, null)?.let { + getString(PrefKeys.LANGUAGE_PREFS, null)?.let { gson.fromJson(it, object : TypeToken>() {}.type) as Map } ?: mapOf() } catch (e: Throwable) { @@ -155,7 +168,7 @@ class LocalPreferences(context: Context) { mapOf() } - val hideDeleteRequestInfo = getBoolean(myPrefs.HIDE_DELETE_REQUEST_INFO, false) + val hideDeleteRequestInfo = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, false) return Account( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), @@ -173,13 +186,13 @@ class LocalPreferences(context: Context) { } fun saveLastRead(route: String, timestampInSecs: Long) { - encryptedPreferences.edit().apply { + encryptedPreferences(currentAccount).edit().apply { putLong(PrefKeys.LAST_READ(route), timestampInSecs) }.apply() } fun loadLastRead(route: String): Long { - encryptedPreferences.run { + encryptedPreferences(currentAccount).run { return getLong(PrefKeys.LAST_READ(route), 0) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt index 0173fe3bd..891303243 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt @@ -21,7 +21,7 @@ object NotificationCache { val scope = CoroutineScope(Job() + Dispatchers.IO) scope.launch { - LocalPreferences(context).saveLastRead(route, timestampInSecs) + LocalPreferences.saveLastRead(route, timestampInSecs) live.invalidateData() } } @@ -30,7 +30,7 @@ object NotificationCache { fun load(route: String, context: Context): Long { var lastTime = lastReadByRoute[route] if (lastTime == null) { - lastTime = LocalPreferences(context).loadLastRead(route) + lastTime = LocalPreferences.loadLastRead(route) lastReadByRoute[route] = lastTime } return lastTime diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index cdb3aab35..a11394367 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -14,7 +14,6 @@ import coil.ImageLoader import coil.decode.GifDecoder import coil.decode.ImageDecoderDecoder import coil.decode.SvgDecoder -import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.service.nip19.Nip19 import com.vitorpamplona.amethyst.service.relays.Client @@ -54,7 +53,7 @@ class MainActivity : FragmentActivity() { // A surface container using the 'background' color from the theme Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) { val accountStateViewModel: AccountStateViewModel = viewModel { - AccountStateViewModel(LocalPreferences(applicationContext)) + AccountStateViewModel() } AccountScreen(accountStateViewModel, startingPage) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt index f206ac2d0..87685baee 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AccountSwitchBottomSheet.kt @@ -1,54 +1,81 @@ package com.vitorpamplona.amethyst.ui.navigation +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme import androidx.compose.material.ModalBottomSheetState +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Logout +import androidx.compose.material.icons.outlined.Visibility +import androidx.compose.material.icons.outlined.VisibilityOff import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.autofill.AutofillNode +import androidx.compose.ui.autofill.AutofillType import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.layout.boundsInWindow +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalAutofill +import androidx.compose.ui.platform.LocalAutofillTree import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.RoboHashCache import com.vitorpamplona.amethyst.ui.components.AsyncImageProxy import com.vitorpamplona.amethyst.ui.components.ResizeImage import com.vitorpamplona.amethyst.ui.note.toShortenHex +import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import kotlinx.coroutines.launch -@OptIn(ExperimentalMaterialApi::class) +@OptIn(ExperimentalMaterialApi::class, ExperimentalComposeUiApi::class) @Composable fun AccountSwitchBottomSheet( accountViewModel: AccountViewModel, + accountStateViewModel: AccountStateViewModel, sheetState: ModalBottomSheetState ) { val coroutineScope = rememberCoroutineScope() val context = LocalContext.current - val localPrefs = LocalPreferences(context) - val accounts = localPrefs.findAllLocalAccounts() + val accounts = LocalPreferences.findAllLocalAccounts() val accountState by accountViewModel.accountLiveData.observeAsState() val account = accountState?.account ?: return @@ -56,9 +83,7 @@ fun AccountSwitchBottomSheet( val accountUserState by account.userProfile().live().metadata.observeAsState() val accountUser = accountUserState?.user ?: return - LaunchedEffect(key1 = accountUser) { - localPrefs.saveCurrentAccountMetadata(account) - } + var popupExpanded by remember { mutableStateOf(false) } Column { Row( @@ -114,9 +139,98 @@ fun AccountSwitchBottomSheet( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { - TextButton(onClick = { coroutineScope.launch { sheetState.hide() } }) { + TextButton(onClick = { popupExpanded = true }) { Text("Add New Account") } } } + + if (popupExpanded) { + Dialog( + onDismissRequest = { popupExpanded = false }, + properties = DialogProperties(usePlatformDefaultWidth = false) + ) { + Surface(modifier = Modifier.fillMaxSize()) { + Column( + modifier = Modifier + .fillMaxHeight() + .background(MaterialTheme.colors.surface), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + val key = remember { mutableStateOf(TextFieldValue("")) } + var errorMessage by remember { mutableStateOf("") } + var showPassword by remember { + mutableStateOf(false) + } + val autofillNode = AutofillNode( + autofillTypes = listOf(AutofillType.Password), + onFill = { key.value = TextFieldValue(it) } + ) + val autofill = LocalAutofill.current + LocalAutofillTree.current += autofillNode + + OutlinedTextField( + modifier = Modifier + .onGloballyPositioned { coordinates -> + autofillNode.boundingBox = coordinates.boundsInWindow() + } + .onFocusChanged { focusState -> + autofill?.run { + if (focusState.isFocused) { + requestAutofillForNode(autofillNode) + } else { + cancelAutofillForNode(autofillNode) + } + } + }, + value = key.value, + onValueChange = { key.value = it }, + keyboardOptions = KeyboardOptions( + autoCorrect = false, + keyboardType = KeyboardType.Password, + imeAction = ImeAction.Go + ), + placeholder = { + Text( + text = stringResource(R.string.nsec_npub_hex_private_key), + color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) + ) + }, + trailingIcon = { + IconButton(onClick = { showPassword = !showPassword }) { + Icon( + imageVector = if (showPassword) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility, + contentDescription = if (showPassword) { + stringResource(R.string.show_password) + } else { + stringResource( + R.string.hide_password + ) + } + ) + } + }, + visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), + keyboardActions = KeyboardActions( + onGo = { + try { + accountStateViewModel.login(key.value.text) + } catch (e: Exception) { + errorMessage = context.getString(R.string.invalid_key) + } + } + ) + ) + if (errorMessage.isNotBlank()) { + Text( + text = errorMessage, + color = MaterialTheme.colors.error, + style = MaterialTheme.typography.caption + ) + } + } + } + } + } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index e57a4ae1b..3321b42df 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -17,7 +17,7 @@ import nostr.postr.Persona import nostr.postr.bechToBytes import java.util.regex.Pattern -class AccountStateViewModel(private val localPreferences: LocalPreferences) : ViewModel() { +class AccountStateViewModel() : ViewModel() { private val _accountContent = MutableStateFlow(AccountState.LoggedOff) val accountContent = _accountContent.asStateFlow() @@ -26,7 +26,7 @@ class AccountStateViewModel(private val localPreferences: LocalPreferences) : Vi // Keeps it in the the UI thread to void blinking the login page. // viewModelScope.launch(Dispatchers.IO) { - localPreferences.loadFromEncryptedStorage()?.let { + LocalPreferences.loadFromEncryptedStorage()?.let { login(it) } // } @@ -47,18 +47,19 @@ class AccountStateViewModel(private val localPreferences: LocalPreferences) : Vi Account(Persona(Hex.decode(key))) } - localPreferences.saveToEncryptedStorage(account) - + LocalPreferences.saveToEncryptedStorage(account) login(account) } fun newKey() { val account = Account(Persona()) - localPreferences.saveToEncryptedStorage(account) + LocalPreferences.saveToEncryptedStorage(account) login(account) } fun login(account: Account) { + LocalPreferences.setCurrentAccount(account) + if (account.loggedIn.privKey != null) { _accountContent.update { AccountState.LoggedIn(account) } } else { @@ -77,7 +78,7 @@ class AccountStateViewModel(private val localPreferences: LocalPreferences) : Vi private val saveListener: (com.vitorpamplona.amethyst.model.AccountState) -> Unit = { GlobalScope.launch(Dispatchers.IO) { - localPreferences.saveToEncryptedStorage(it.account) + LocalPreferences.saveToEncryptedStorage(it.account) } } @@ -100,6 +101,6 @@ class AccountStateViewModel(private val localPreferences: LocalPreferences) : Vi _accountContent.update { AccountState.LoggedOff } - localPreferences.clearEncryptedStorage() + LocalPreferences.clearEncryptedStorage() } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt index e296fec90..a1cb6f101 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt @@ -47,7 +47,7 @@ fun MainScreen(accountViewModel: AccountViewModel, accountStateViewModel: Accoun ModalBottomSheetLayout( sheetState = sheetState, sheetContent = { - AccountSwitchBottomSheet(accountViewModel = accountViewModel, sheetState = sheetState) + AccountSwitchBottomSheet(accountViewModel = accountViewModel, accountStateViewModel = accountStateViewModel, sheetState = sheetState) } ) { Scaffold(