mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-06 03:18:23 +00:00
This change moves the language preference from being an individual account setting to a global application-wide setting. The `language` property has been removed from the `Account` model and added to the `AmberSettings` model. All related logic for saving, loading, and applying the language preference has been updated to reflect this new global scope. The application now loads and applies the language setting on startup.
620 lines
23 KiB
Kotlin
620 lines
23 KiB
Kotlin
package com.greenart7c3.nostrsigner
|
|
|
|
import android.annotation.SuppressLint
|
|
import android.content.Context
|
|
import android.content.SharedPreferences
|
|
import android.util.Log
|
|
import android.util.LruCache
|
|
import androidx.compose.runtime.Immutable
|
|
import androidx.core.content.edit
|
|
import com.greenart7c3.nostrsigner.models.Account
|
|
import com.greenart7c3.nostrsigner.models.AmberSettings
|
|
import com.greenart7c3.nostrsigner.models.defaultAppRelays
|
|
import com.greenart7c3.nostrsigner.models.defaultIndexerRelays
|
|
import com.greenart7c3.nostrsigner.okhttp.HttpClientManager
|
|
import com.greenart7c3.nostrsigner.ui.parseBiometricsTimeType
|
|
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
|
|
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
|
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
|
import java.io.File
|
|
import kotlin.collections.component1
|
|
import kotlin.collections.component2
|
|
import kotlin.collections.iterator
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.runBlocking
|
|
import kotlinx.coroutines.withContext
|
|
|
|
private enum class PrefKeys(val key: String) {
|
|
NOSTR_PRIVKEY("nostr_privkey"),
|
|
NOSTR_PUBKEY("nostr_pubkey"),
|
|
ACCOUNT_NAME("account_name"),
|
|
SIGN_POLICY("default_sign_policy"),
|
|
SEED_WORDS("seed_words"),
|
|
PROFILE_URL("profile_url"),
|
|
LAST_METADATA_UPDATE("last_metadata_update"),
|
|
LAST_CHECK("last_check"),
|
|
DID_BACKUP("did_backup"),
|
|
}
|
|
|
|
private enum class SettingsKeys(val key: String) {
|
|
DEFAULT_RELAYS("default_relays"),
|
|
DEFAULT_PROFILE_RELAYS("default_profile_relays"),
|
|
LAST_BIOMETRICS_TIME("last_biometrics_time"),
|
|
USE_AUTH("use_auth"),
|
|
BIOMETRICS_TYPE("biometrics_type"),
|
|
USE_PIN("use_pin"),
|
|
RATIONALE("rationale"),
|
|
CURRENT_ACCOUNT("currently_logged_in_account"),
|
|
PIN("pin"),
|
|
SAVED_ACCOUNTS("all_saved_accounts"),
|
|
USE_PROXY("use_proxy"),
|
|
PROXY_PORT("proxy_port"),
|
|
BATERRY_OPTIMIZATION("battery_optimization"),
|
|
KILL_SWITCH("kill_switch"),
|
|
LANGUAGE_PREFS("languagePreferences"),
|
|
}
|
|
|
|
@Immutable
|
|
data class AccountInfo(
|
|
val npub: String,
|
|
val hasPrivKey: Boolean,
|
|
)
|
|
|
|
object LocalPreferences {
|
|
private const val COMMA = ","
|
|
private var currentAccount: String? = null
|
|
private var accountCache = LruCache<String, Account>(10)
|
|
|
|
fun allLegacySavedAccounts(context: Context): List<AccountInfo> {
|
|
return legacySavedAccounts(context).map { npub ->
|
|
AccountInfo(
|
|
npub,
|
|
true,
|
|
)
|
|
}.toSet().toList()
|
|
}
|
|
|
|
fun allSavedAccounts(context: Context): List<AccountInfo> {
|
|
return savedAccounts(context).map { npub ->
|
|
AccountInfo(
|
|
npub,
|
|
true,
|
|
)
|
|
}.toSet().toList()
|
|
}
|
|
|
|
fun currentAccount(context: Context): String? {
|
|
if (currentAccount == null) {
|
|
Log.d(Amber.TAG, "currentAccount is null fetching from shared preferences")
|
|
currentAccount = sharedPrefs(context).getString(SettingsKeys.CURRENT_ACCOUNT.key, null)
|
|
if (currentAccount == null) {
|
|
Log.d(Amber.TAG, "currentAccount is null fetching from all saved accounts")
|
|
currentAccount = allSavedAccounts(context).firstOrNull()?.npub
|
|
}
|
|
}
|
|
return currentAccount
|
|
}
|
|
|
|
private fun updateCurrentAccount(context: Context, npub: String) {
|
|
if (currentAccount != npub) {
|
|
currentAccount = npub
|
|
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
putString(SettingsKeys.CURRENT_ACCOUNT.key, npub)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun shouldShowRationale(context: Context): Boolean? {
|
|
if (!sharedPrefs(context).contains(SettingsKeys.RATIONALE.key)) {
|
|
return null
|
|
}
|
|
return sharedPrefs(context).getBoolean(SettingsKeys.RATIONALE.key, true)
|
|
}
|
|
|
|
fun updateShouldShowRationale(context: Context, value: Boolean) {
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
putBoolean(SettingsKeys.RATIONALE.key, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun saveSettingsToEncryptedStorage(settings: AmberSettings) {
|
|
val context = Amber.instance
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
putStringSet(SettingsKeys.DEFAULT_RELAYS.key, settings.defaultRelays.map { it.url }.toSet())
|
|
putStringSet(SettingsKeys.DEFAULT_PROFILE_RELAYS.key, settings.defaultProfileRelays.map { it.url }.toSet())
|
|
putLong(SettingsKeys.LAST_BIOMETRICS_TIME.key, settings.lastBiometricsTime)
|
|
putBoolean(SettingsKeys.USE_AUTH.key, settings.useAuth)
|
|
putInt(SettingsKeys.BIOMETRICS_TYPE.key, settings.biometricsTimeType.screenCode)
|
|
putBoolean(SettingsKeys.USE_PIN.key, settings.usePin)
|
|
putBoolean(SettingsKeys.USE_PROXY.key, settings.useProxy)
|
|
putInt(SettingsKeys.PROXY_PORT.key, settings.proxyPort)
|
|
putBoolean(SettingsKeys.KILL_SWITCH.key, settings.killSwitch.value)
|
|
putString(SettingsKeys.LANGUAGE_PREFS.key, settings.language)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun getBatteryOptimization(context: Context): Boolean {
|
|
return sharedPrefs(context).getBoolean(SettingsKeys.BATERRY_OPTIMIZATION.key, false)
|
|
}
|
|
|
|
fun updateBatteryOptimization(context: Context, value: Boolean) {
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
putBoolean(SettingsKeys.BATERRY_OPTIMIZATION.key, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun setLastCheck(context: Context, npub: String, time: Long) {
|
|
sharedPrefs(context, npub).edit {
|
|
apply {
|
|
putLong(PrefKeys.LAST_CHECK.key, time)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun setLastMetadataUpdate(context: Context, npub: String, time: Long) {
|
|
sharedPrefs(context, npub).edit {
|
|
apply {
|
|
putLong(PrefKeys.LAST_METADATA_UPDATE.key, time)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun loadPinFromEncryptedStorage(): String? {
|
|
val context = Amber.instance
|
|
return sharedPrefs(context).getString(SettingsKeys.PIN.key, null)
|
|
}
|
|
|
|
fun savePinToEncryptedStorage(pin: String?) {
|
|
val context = Amber.instance
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
if (pin == null) {
|
|
remove(SettingsKeys.PIN.key)
|
|
} else {
|
|
putString(SettingsKeys.PIN.key, pin)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
suspend fun reloadApp() {
|
|
val context = Amber.instance
|
|
currentAccount = null
|
|
savedAccounts = null
|
|
accountCache.evictAll()
|
|
allSavedAccounts(context).forEach {
|
|
loadFromEncryptedStorage(context, it.npub)
|
|
}
|
|
context.settings = loadSettingsFromEncryptedStorage(context)
|
|
}
|
|
|
|
fun loadSettingsFromEncryptedStorage(context: Context = Amber.instance): AmberSettings {
|
|
checkNotInMainThread()
|
|
sharedPrefs(context).apply {
|
|
val proxyPort = getInt(SettingsKeys.PROXY_PORT.key, 9050)
|
|
HttpClientManager.setDefaultProxyOnPort(proxyPort)
|
|
|
|
return AmberSettings(
|
|
defaultRelays = getStringSet(SettingsKeys.DEFAULT_RELAYS.key, null)?.mapNotNull {
|
|
RelayUrlNormalizer.normalizeOrNull(it)
|
|
} ?: defaultAppRelays,
|
|
defaultProfileRelays = getStringSet(SettingsKeys.DEFAULT_PROFILE_RELAYS.key, null)?.mapNotNull {
|
|
RelayUrlNormalizer.normalizeOrNull(it)
|
|
} ?: defaultIndexerRelays,
|
|
lastBiometricsTime = getLong(SettingsKeys.LAST_BIOMETRICS_TIME.key, 0),
|
|
useAuth = getBoolean(SettingsKeys.USE_AUTH.key, false),
|
|
biometricsTimeType = parseBiometricsTimeType(getInt(SettingsKeys.BIOMETRICS_TYPE.key, 0)),
|
|
usePin = getBoolean(SettingsKeys.USE_PIN.key, false),
|
|
useProxy = getBoolean(SettingsKeys.USE_PROXY.key, false),
|
|
proxyPort = getInt(SettingsKeys.PROXY_PORT.key, 9050),
|
|
killSwitch = MutableStateFlow(getBoolean(SettingsKeys.KILL_SWITCH.key, false)),
|
|
language = getString(SettingsKeys.LANGUAGE_PREFS.key, null),
|
|
)
|
|
}
|
|
}
|
|
|
|
private var savedAccounts: List<String>? = null
|
|
|
|
@Suppress("DEPRECATION")
|
|
private fun legacySavedAccounts(context: Context): List<String> {
|
|
return encryptedPreferences(context)
|
|
.getString(SettingsKeys.SAVED_ACCOUNTS.key, null)?.split(COMMA) ?: listOf()
|
|
}
|
|
|
|
private fun savedAccounts(context: Context): List<String> {
|
|
if (savedAccounts == null) {
|
|
savedAccounts = sharedPrefs(context)
|
|
.getString(SettingsKeys.SAVED_ACCOUNTS.key, null)?.split(COMMA) ?: listOf()
|
|
}
|
|
return savedAccounts!!
|
|
}
|
|
|
|
private fun updateSavedAccounts(context: Context, accounts: List<String>) {
|
|
if (savedAccounts != accounts) {
|
|
savedAccounts = accounts
|
|
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
putString(SettingsKeys.SAVED_ACCOUNTS.key, accounts.joinToString(COMMA).ifBlank { null })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun getDirPath(context: Context): String {
|
|
return "${context.filesDir.parent}/shared_prefs/"
|
|
}
|
|
|
|
private fun addAccount(context: Context, npub: String) {
|
|
val accounts = savedAccounts(context).toMutableList()
|
|
if (npub !in accounts) {
|
|
accounts.add(npub)
|
|
updateSavedAccounts(context, accounts)
|
|
}
|
|
}
|
|
|
|
private fun setCurrentAccount(context: Context, account: Account) {
|
|
updateCurrentAccount(context, account.npub)
|
|
addAccount(context, account.npub)
|
|
}
|
|
|
|
fun switchToAccount(context: Context, npub: String) {
|
|
updateCurrentAccount(context, npub)
|
|
}
|
|
|
|
fun containsAccount(context: Context, npub: String): Boolean {
|
|
return savedAccounts(context).contains(npub)
|
|
}
|
|
|
|
/**
|
|
* Removes the account from the app level shared preferences
|
|
*/
|
|
private fun removeAccount(context: Context, npub: String) {
|
|
val accounts = savedAccounts(context).toMutableList()
|
|
if (accounts.remove(npub)) {
|
|
updateSavedAccounts(context, accounts)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deletes the npub-specific shared preference file
|
|
*/
|
|
private fun deleteUserPreferenceFile(context: Context, npub: String) {
|
|
val prefsDir = File(getDirPath(context))
|
|
prefsDir.list()?.forEach {
|
|
if (it.contains(npub)) {
|
|
try {
|
|
val result = File(prefsDir, it).delete()
|
|
Log.d(Amber.TAG, "deleted $it: $result")
|
|
} catch (e: Exception) {
|
|
Log.d(Amber.TAG, "failed to delete $it", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun deleteLegacyUserPreferenceFile(context: Context, npub: String) {
|
|
val prefsDir = File(getDirPath(context))
|
|
prefsDir.list()?.forEach {
|
|
if (it.contains(npub) && it.startsWith("secret_keeper")) {
|
|
try {
|
|
val result = File(prefsDir, it).delete()
|
|
Log.d(Amber.TAG, "deleted $it: $result")
|
|
} catch (e: Exception) {
|
|
Log.d(Amber.TAG, "failed to delete $it", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun existsLegacySettings(context: Context): Boolean {
|
|
val prefsDir = File(getDirPath(context))
|
|
var result = false
|
|
prefsDir.list()?.forEach {
|
|
if (it == "secret_keeper.xml") {
|
|
result = true
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
fun deleteSettingsPreferenceFile(context: Context) {
|
|
val prefsDir = File(getDirPath(context))
|
|
prefsDir.list()?.forEach {
|
|
if (it == "secret_keeper.xml") {
|
|
try {
|
|
val result = File(prefsDir, it).delete()
|
|
Log.d(Amber.TAG, "deleted $it: $result")
|
|
} catch (e: Exception) {
|
|
Log.d(Amber.TAG, "failed to delete $it", e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Deprecated("Use sharedPrefs instead")
|
|
private fun encryptedPreferences(
|
|
context: Context,
|
|
npub: String? = null,
|
|
): SharedPreferences {
|
|
return EncryptedStorage.preferences(npub, context)
|
|
}
|
|
|
|
private fun sharedPrefs(
|
|
context: Context,
|
|
npub: String? = null,
|
|
): SharedPreferences {
|
|
val preferenceFile = if (npub == null) "prefs" else "prefs_$npub"
|
|
return context.getSharedPreferences(preferenceFile, Context.MODE_PRIVATE)
|
|
}
|
|
|
|
private suspend fun deleteUserDataStoreFile(context: Context, npub: String) {
|
|
DataStoreAccess.clearCacheForNpub(context, npub)
|
|
}
|
|
|
|
/**
|
|
* Clears the preferences for a given npub, deletes the preferences xml file,
|
|
* and switches the user to the first account in the list if it exists
|
|
*
|
|
* We need to use `commit()` to write changes to disk and release the file
|
|
* lock so that it can be deleted. If we use `apply()` there is a race
|
|
* condition and the file will probably not be deleted
|
|
*/
|
|
@SuppressLint("ApplySharedPref")
|
|
fun updatePrefsForLogout(npub: String, context: Context): Boolean {
|
|
accountCache.remove(npub)
|
|
val userPrefs = sharedPrefs(context, npub)
|
|
userPrefs.edit(commit = true) { clear() }
|
|
removeAccount(context, npub)
|
|
deleteUserPreferenceFile(context, npub)
|
|
|
|
runBlocking { deleteUserDataStoreFile(context, npub) }
|
|
|
|
if (savedAccounts(context).isEmpty()) {
|
|
val appPrefs = sharedPrefs(context)
|
|
appPrefs.edit(commit = true) { clear() }
|
|
return true
|
|
} else if (currentAccount(context) == npub) {
|
|
updateCurrentAccount(context, savedAccounts(context).elementAt(0))
|
|
return false
|
|
}
|
|
return false
|
|
}
|
|
|
|
fun updatePrefsForLogin(context: Context, account: Account) {
|
|
setCurrentAccount(context, account)
|
|
Amber.instance.applicationIOScope.launch {
|
|
saveToEncryptedStorage(context, account)
|
|
}
|
|
}
|
|
|
|
suspend fun saveToEncryptedStorage(context: Context, account: Account) {
|
|
val prefs = sharedPrefs(context = context, account.npub)
|
|
prefs.edit {
|
|
apply {
|
|
account.signer.keyPair.pubKey.let { putString(PrefKeys.NOSTR_PUBKEY.key, it.toHexKey()) }
|
|
putString(PrefKeys.ACCOUNT_NAME.key, account.name.value)
|
|
putString(PrefKeys.PROFILE_URL.key, account.picture.value)
|
|
putInt(PrefKeys.SIGN_POLICY.key, account.signPolicy)
|
|
putBoolean(PrefKeys.DID_BACKUP.key, account.didBackup)
|
|
}
|
|
}
|
|
|
|
account.signer.keyPair.privKey?.toHexKey()?.let {
|
|
DataStoreAccess.saveEncryptedKey(context, account.npub, DataStoreAccess.NOSTR_PRIVKEY, it)
|
|
}
|
|
|
|
DataStoreAccess.saveEncryptedKey(
|
|
context,
|
|
account.npub,
|
|
DataStoreAccess.SEED_WORDS,
|
|
account.seedWords.joinToString(" "),
|
|
)
|
|
accountCache.put(account.npub, account)
|
|
}
|
|
|
|
suspend fun loadFromEncryptedStorage(context: Context): Account? {
|
|
currentAccount(context)?.let {
|
|
return loadFromEncryptedStorage(context, it)
|
|
}
|
|
return null
|
|
}
|
|
|
|
suspend fun allAccounts(context: Context): List<Account> {
|
|
val accountInfos = allSavedAccounts(context)
|
|
return accountInfos.mapNotNull {
|
|
loadFromEncryptedStorage(context, it.npub)
|
|
}
|
|
}
|
|
|
|
fun loadFromEncryptedStorageSync(context: Context, npub: String? = null): Account? {
|
|
if (savedAccounts == null || accountCache.size() == 0 || savedAccounts?.size != accountCache.size()) {
|
|
Log.d(Amber.TAG, "accountCache is null loading accounts")
|
|
runBlocking {
|
|
allSavedAccounts(context).forEach {
|
|
loadFromEncryptedStorage(context, it.npub)
|
|
}
|
|
}
|
|
}
|
|
if (npub == null) {
|
|
val currentAccount = currentAccount(context) ?: return null
|
|
return accountCache[currentAccount]
|
|
}
|
|
return accountCache[npub]
|
|
}
|
|
|
|
fun setAccountName(
|
|
context: Context,
|
|
npub: String,
|
|
value: String,
|
|
) {
|
|
sharedPrefs(context, npub).edit {
|
|
apply {
|
|
putString(PrefKeys.ACCOUNT_NAME.key, value)
|
|
}
|
|
}
|
|
accountCache.get(npub)?.name?.tryEmit(value)
|
|
}
|
|
|
|
fun getAccountName(context: Context, npub: String): String {
|
|
sharedPrefs(context, npub).apply {
|
|
return getString(PrefKeys.ACCOUNT_NAME.key, "") ?: ""
|
|
}
|
|
}
|
|
|
|
fun updateProxy(
|
|
context: Context,
|
|
useProxy: Boolean,
|
|
port: Int,
|
|
) {
|
|
sharedPrefs(context).edit {
|
|
apply {
|
|
putBoolean(SettingsKeys.USE_PROXY.key, useProxy)
|
|
putInt(SettingsKeys.PROXY_PORT.key, port)
|
|
}
|
|
}
|
|
Amber.instance.settings = loadSettingsFromEncryptedStorage()
|
|
HttpClientManager.setDefaultProxyOnPort(port)
|
|
}
|
|
|
|
suspend fun loadFromEncryptedStorage(context: Context, npub: String): Account? {
|
|
if (accountCache.get(npub) != null) {
|
|
return accountCache.get(npub)
|
|
}
|
|
sharedPrefs(context, npub).apply {
|
|
val pubKey = getString(PrefKeys.NOSTR_PUBKEY.key, null) ?: return null
|
|
val privKey = DataStoreAccess.getEncryptedKey(context, npub, DataStoreAccess.NOSTR_PRIVKEY)
|
|
val name = getString(PrefKeys.ACCOUNT_NAME.key, "") ?: ""
|
|
val picture = getString(PrefKeys.PROFILE_URL.key, "") ?: ""
|
|
val signPolicy = getInt(PrefKeys.SIGN_POLICY.key, 1)
|
|
val savedSeedWords = DataStoreAccess.getEncryptedKey(context, npub, DataStoreAccess.SEED_WORDS)
|
|
val seedWords = savedSeedWords?.split(" ")?.toSet() ?: emptySet()
|
|
val didBackup = getBoolean(PrefKeys.DID_BACKUP.key, true)
|
|
|
|
val account =
|
|
Account(
|
|
signer = NostrSignerInternal(KeyPair(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray())),
|
|
name = MutableStateFlow(name),
|
|
picture = MutableStateFlow(picture),
|
|
signPolicy = signPolicy,
|
|
seedWords = seedWords,
|
|
didBackup = didBackup,
|
|
)
|
|
accountCache.put(npub, account)
|
|
return account
|
|
}
|
|
}
|
|
|
|
suspend fun didMigrateFromLegacyStorage(context: Context, npub: String): Boolean {
|
|
val existingPrivKey = DataStoreAccess.getEncryptedKey(context, npub, DataStoreAccess.NOSTR_PRIVKEY)
|
|
return !existingPrivKey.isNullOrBlank()
|
|
}
|
|
|
|
@Suppress("DEPRECATION")
|
|
suspend fun migrateFromSharedPrefs(context: Context, npub: String) {
|
|
withContext(Dispatchers.IO) {
|
|
if (didMigrateFromLegacyStorage(context, npub)) return@withContext
|
|
val legacyPrefs = encryptedPreferences(context, npub)
|
|
val privKey = legacyPrefs.getString(PrefKeys.NOSTR_PRIVKEY.key, null)
|
|
if (privKey.isNullOrBlank()) {
|
|
return@withContext
|
|
}
|
|
val seedWords = legacyPrefs.getString(PrefKeys.SEED_WORDS.key, null)
|
|
DataStoreAccess.saveEncryptedKey(context, npub, DataStoreAccess.NOSTR_PRIVKEY, privKey)
|
|
if (!seedWords.isNullOrBlank()) {
|
|
DataStoreAccess.saveEncryptedKey(context, npub, DataStoreAccess.SEED_WORDS, seedWords)
|
|
}
|
|
legacyPrefs.edit {
|
|
apply {
|
|
remove(PrefKeys.NOSTR_PRIVKEY.key)
|
|
remove(PrefKeys.SEED_WORDS.key)
|
|
}
|
|
}
|
|
migrateUserSharedPrefs(context, npub)
|
|
deleteLegacyUserPreferenceFile(context, npub)
|
|
}
|
|
}
|
|
|
|
@Suppress("DEPRECATION")
|
|
private fun migrateUserSharedPrefs(context: Context, npub: String) {
|
|
val legacyPrefs = encryptedPreferences(context, npub)
|
|
val sharedPrefs = sharedPrefs(context, npub)
|
|
for ((key, value) in legacyPrefs.all) {
|
|
when (value) {
|
|
is String -> sharedPrefs.edit { putString(key, value) }
|
|
is Boolean -> sharedPrefs.edit { putBoolean(key, value) }
|
|
is Int -> sharedPrefs.edit { putInt(key, value) }
|
|
is Long -> sharedPrefs.edit { putLong(key, value) }
|
|
is Float -> sharedPrefs.edit { putFloat(key, value) }
|
|
is Set<*> -> {
|
|
@Suppress("UNCHECKED_CAST")
|
|
if (value.all { it is String }) {
|
|
sharedPrefs.edit { putStringSet(key, value as Set<String>) }
|
|
}
|
|
}
|
|
else -> {
|
|
// Ignore unsupported types
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Suppress("DEPRECATION")
|
|
fun migrateSettings(context: Context) {
|
|
val settingsPrefs = sharedPrefs(context)
|
|
val legacySettingsPrefs = encryptedPreferences(context)
|
|
for ((key, value) in legacySettingsPrefs.all) {
|
|
when (value) {
|
|
is String -> settingsPrefs.edit { putString(key, value) }
|
|
is Boolean -> settingsPrefs.edit { putBoolean(key, value) }
|
|
is Int -> settingsPrefs.edit { putInt(key, value) }
|
|
is Long -> settingsPrefs.edit { putLong(key, value) }
|
|
is Float -> settingsPrefs.edit { putFloat(key, value) }
|
|
is Set<*> -> {
|
|
@Suppress("UNCHECKED_CAST")
|
|
if (value.all { it is String }) {
|
|
settingsPrefs.edit { putStringSet(key, value as Set<String>) }
|
|
}
|
|
}
|
|
else -> {
|
|
// Ignore unsupported types
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun migrateTorSettings(context: Context) {
|
|
if (sharedPrefs(context).contains(SettingsKeys.USE_PROXY.key)) return
|
|
|
|
val useProxy = allSavedAccounts(context).any {
|
|
sharedPrefs(context, it.npub).getBoolean(SettingsKeys.USE_PROXY.key, false)
|
|
}
|
|
val proxyPort: Int = allSavedAccounts(context).firstNotNullOfOrNull {
|
|
if (sharedPrefs(context, it.npub).getBoolean(SettingsKeys.USE_PROXY.key, false)) {
|
|
sharedPrefs(context, it.npub).getInt(SettingsKeys.PROXY_PORT.key, 9050)
|
|
} else {
|
|
null
|
|
}
|
|
} ?: 9050
|
|
saveSettingsToEncryptedStorage(
|
|
settings = loadSettingsFromEncryptedStorage(context).copy(
|
|
useProxy = useProxy,
|
|
proxyPort = proxyPort,
|
|
),
|
|
)
|
|
}
|
|
}
|