Update v1.2.0
This commit is contained in:
@@ -16,10 +16,18 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
import android.os.Build
|
||||
|
||||
class SettingsStore(context: Context) {
|
||||
private val appContext = context.applicationContext
|
||||
companion object {
|
||||
private val Context.dataStore by preferencesDataStore("settings")
|
||||
private val ACTIVE_PROFILE = intPreferencesKey("active_profile")
|
||||
private val SHOW_SYSTEM_APPS = booleanPreferencesKey("show_system_apps")
|
||||
private val LOGGING_ENABLED = booleanPreferencesKey("logging_enabled")
|
||||
private val WDTT_LINK = stringPreferencesKey("wdtt_link")
|
||||
private val WDTT_LINK_MODE = booleanPreferencesKey("wdtt_link_mode")
|
||||
|
||||
private val PEER = stringPreferencesKey("peer")
|
||||
private val VK_HASHES = stringPreferencesKey("vk_hashes")
|
||||
private val SECONDARY_VK_HASH = stringPreferencesKey("secondary_vk_hash")
|
||||
@@ -83,6 +91,18 @@ class SettingsStore(context: Context) {
|
||||
private val UPDATE_DIALOG_LAST_ACTION_VERSION = stringPreferencesKey("update_dialog_last_action_version")
|
||||
private val UPDATE_DIALOG_LAST_ACTION = stringPreferencesKey("update_dialog_last_action")
|
||||
private val UPDATE_DIALOG_LAST_ACTION_AT = longPreferencesKey("update_dialog_last_action_at")
|
||||
|
||||
private fun <T> getProfileKey(baseKey: Preferences.Key<T>, profile: Int): Preferences.Key<T> {
|
||||
if (profile == 0) return baseKey
|
||||
val newName = "${baseKey.name}_$profile"
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return when (baseKey) {
|
||||
PEER, VK_HASHES, SECONDARY_VK_HASH, PROTOCOL, SNI, USER_AGENT, DEPLOY_IP, DEPLOY_LOGIN, DEPLOY_PASSWORD, DEPLOY_PASSWORD_ENCRYPTED, DEPLOY_SSH_PORT, EXCLUDED_APPS, CONNECTION_PASSWORD, CONNECTION_PASSWORD_ENCRYPTED, DEPLOY_MAIN_PASSWORD, DEPLOY_MAIN_PASSWORD_ENCRYPTED, DEPLOY_ADMIN_ID, DEPLOY_ADMIN_ID_ENCRYPTED, DEPLOY_BOT_TOKEN, DEPLOY_BOT_TOKEN_ENCRYPTED, PROXY_MODE, PROXY_HOST, CAPTCHA_MODE, CAPTCHA_SOLVE_METHOD, CAPTCHA_WBV_SOLVE_METHOD, WDTT_LINK -> stringPreferencesKey(newName) as Preferences.Key<T>
|
||||
WORKERS_PER_HASH, LISTEN_PORT, SERVER_DTLS_PORT, SERVER_WG_PORT, PROXY_PORT -> intPreferencesKey(newName) as Preferences.Key<T>
|
||||
MANUAL_PORTS_ENABLED, NO_DTLS, NO_DNS, IS_WHITELIST, WDTT_LINK_MODE -> booleanPreferencesKey(newName) as Preferences.Key<T>
|
||||
else -> throw IllegalArgumentException("Unsupported key type: ${baseKey.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val dataStore = appContext.dataStore
|
||||
@@ -94,65 +114,151 @@ class SettingsStore(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
val peer: Flow<String> = dataStore.data.map { it[PEER] ?: "" }
|
||||
val vkHashes: Flow<String> = dataStore.data.map { it[VK_HASHES] ?: "" }
|
||||
val secondaryVkHash: Flow<String> = dataStore.data.map { it[SECONDARY_VK_HASH] ?: "" }
|
||||
val workersPerHash: Flow<Int> = dataStore.data.map { it[WORKERS_PER_HASH] ?: 16 }
|
||||
val protocol: Flow<String> = dataStore.data.map { it[PROTOCOL] ?: "udp" }
|
||||
val listenPort: Flow<Int> = dataStore.data.map { it[LISTEN_PORT] ?: 9000 }
|
||||
val manualPortsEnabled: Flow<Boolean> = dataStore.data.map { it[MANUAL_PORTS_ENABLED] ?: false }
|
||||
val serverDtlsPort: Flow<Int> = dataStore.data.map { it[SERVER_DTLS_PORT] ?: 56000 }
|
||||
val serverWgPort: Flow<Int> = dataStore.data.map { it[SERVER_WG_PORT] ?: 56001 }
|
||||
val sni: Flow<String> = dataStore.data.map { it[SNI] ?: "" }
|
||||
val noDns: Flow<Boolean> = dataStore.data.map { it[NO_DNS] ?: false }
|
||||
val userAgent: Flow<String> = dataStore.data.map { it[USER_AGENT] ?: "" }
|
||||
|
||||
val deployIp: Flow<String> = dataStore.data.map { it[DEPLOY_IP] ?: "" }
|
||||
val deployLogin: Flow<String> = dataStore.data.map { it[DEPLOY_LOGIN] ?: "" }
|
||||
val deployPassword: Flow<String> = dataStore.data.map {
|
||||
readSecret(it, DEPLOY_PASSWORD_ENCRYPTED, DEPLOY_PASSWORD)
|
||||
val activeProfile: Flow<Int> = dataStore.data.map { it[ACTIVE_PROFILE] ?: 0 }
|
||||
val showSystemApps: Flow<Boolean> = dataStore.data.map { it[SHOW_SYSTEM_APPS] ?: true }
|
||||
val loggingEnabled: Flow<Boolean> = dataStore.data.map { it[LOGGING_ENABLED] ?: true }
|
||||
val wdttLink: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(WDTT_LINK, profile)] ?: ""
|
||||
}
|
||||
val wdttLinkMode: Flow<Boolean> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(WDTT_LINK_MODE, profile)] ?: false
|
||||
}
|
||||
|
||||
val peer: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PEER, profile)] ?: ""
|
||||
}
|
||||
val vkHashes: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(VK_HASHES, profile)] ?: ""
|
||||
}
|
||||
val secondaryVkHash: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(SECONDARY_VK_HASH, profile)] ?: ""
|
||||
}
|
||||
val workersPerHash: Flow<Int> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(WORKERS_PER_HASH, profile)] ?: 16
|
||||
}
|
||||
val protocol: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PROTOCOL, profile)] ?: "udp"
|
||||
}
|
||||
val listenPort: Flow<Int> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(LISTEN_PORT, profile)] ?: 9000
|
||||
}
|
||||
val manualPortsEnabled: Flow<Boolean> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(MANUAL_PORTS_ENABLED, profile)] ?: false
|
||||
}
|
||||
val serverDtlsPort: Flow<Int> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(SERVER_DTLS_PORT, profile)] ?: 56000
|
||||
}
|
||||
val serverWgPort: Flow<Int> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(SERVER_WG_PORT, profile)] ?: 56001
|
||||
}
|
||||
val sni: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(SNI, profile)] ?: ""
|
||||
}
|
||||
val noDns: Flow<Boolean> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(NO_DNS, profile)] ?: false
|
||||
}
|
||||
val userAgent: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(USER_AGENT, profile)] ?: ""
|
||||
}
|
||||
|
||||
val deployIp: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(DEPLOY_IP, profile)] ?: ""
|
||||
}
|
||||
val deployLogin: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(DEPLOY_LOGIN, profile)] ?: ""
|
||||
}
|
||||
val deployPassword: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
readSecret(prefs, DEPLOY_PASSWORD_ENCRYPTED, DEPLOY_PASSWORD, profile)
|
||||
}
|
||||
val deploySshPort: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(DEPLOY_SSH_PORT, profile)] ?: ""
|
||||
}
|
||||
val excludedApps: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(EXCLUDED_APPS, profile)] ?: ""
|
||||
}
|
||||
val deploySshPort: Flow<String> = dataStore.data.map { it[DEPLOY_SSH_PORT] ?: "" }
|
||||
val excludedApps: Flow<String> = dataStore.data.map { it[EXCLUDED_APPS] ?: "" }
|
||||
|
||||
val detailedLogs: Flow<Boolean> = dataStore.data.map { it[DETAILED_LOGS] ?: false }
|
||||
|
||||
// ═══ Пароли и Управление ═══
|
||||
val connectionPassword: Flow<String> = dataStore.data.map {
|
||||
readSecret(it, CONNECTION_PASSWORD_ENCRYPTED, CONNECTION_PASSWORD)
|
||||
val connectionPassword: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
readSecret(prefs, CONNECTION_PASSWORD_ENCRYPTED, CONNECTION_PASSWORD, profile)
|
||||
}
|
||||
val deployMainPassword: Flow<String> = dataStore.data.map {
|
||||
readSecret(it, DEPLOY_MAIN_PASSWORD_ENCRYPTED, DEPLOY_MAIN_PASSWORD)
|
||||
val deployMainPassword: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
readSecret(prefs, DEPLOY_MAIN_PASSWORD_ENCRYPTED, DEPLOY_MAIN_PASSWORD, profile)
|
||||
}
|
||||
val deployAdminId: Flow<String> = dataStore.data.map {
|
||||
readSecret(it, DEPLOY_ADMIN_ID_ENCRYPTED, DEPLOY_ADMIN_ID)
|
||||
val deployAdminId: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
readSecret(prefs, DEPLOY_ADMIN_ID_ENCRYPTED, DEPLOY_ADMIN_ID, profile)
|
||||
}
|
||||
val deployBotToken: Flow<String> = dataStore.data.map {
|
||||
readSecret(it, DEPLOY_BOT_TOKEN_ENCRYPTED, DEPLOY_BOT_TOKEN)
|
||||
val deployBotToken: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
readSecret(prefs, DEPLOY_BOT_TOKEN_ENCRYPTED, DEPLOY_BOT_TOKEN, profile)
|
||||
}
|
||||
|
||||
// ═══ Proxy Mode ═══
|
||||
val proxyMode: Flow<String> = dataStore.data.map { it[PROXY_MODE] ?: "tun" }
|
||||
val proxyHost: Flow<String> = dataStore.data.map { it[PROXY_HOST] ?: "127.0.0.1" }
|
||||
val proxyPort: Flow<Int> = dataStore.data.map { it[PROXY_PORT] ?: 1080 }
|
||||
val proxyMode: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PROXY_MODE, profile)] ?: "tun"
|
||||
}
|
||||
val proxyHost: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PROXY_HOST, profile)] ?: "127.0.0.1"
|
||||
}
|
||||
val proxyPort: Flow<Int> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PROXY_PORT, profile)] ?: 1080
|
||||
}
|
||||
|
||||
// ═══ Captcha Solve Mode ═══
|
||||
val captchaMode: Flow<String> = dataStore.data.map { it[CAPTCHA_MODE] ?: "auto" }
|
||||
val captchaSolveMethod: Flow<String> = dataStore.data.map { it[CAPTCHA_SOLVE_METHOD] ?: "auto" }
|
||||
val captchaWbvSolveMethod: Flow<String> = dataStore.data.map { it[CAPTCHA_WBV_SOLVE_METHOD] ?: "auto" }
|
||||
val captchaMode: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(CAPTCHA_MODE, profile)] ?: "auto"
|
||||
}
|
||||
val captchaSolveMethod: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(CAPTCHA_SOLVE_METHOD, profile)] ?: "auto"
|
||||
}
|
||||
val captchaWbvSolveMethod: Flow<String> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(CAPTCHA_WBV_SOLVE_METHOD, profile)] ?: "auto"
|
||||
}
|
||||
|
||||
// ═══ VPN Exclusions Mode ═══
|
||||
val isWhitelist: Flow<Boolean> = dataStore.data.map { it[IS_WHITELIST] ?: false }
|
||||
val isWhitelist: Flow<Boolean> = dataStore.data.map { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(IS_WHITELIST, profile)] ?: false
|
||||
}
|
||||
|
||||
// ═══ Theme Mode ═══
|
||||
val themeMode: Flow<String> = dataStore.data.map { it[THEME_MODE] ?: "system" }
|
||||
val isDynamicColor: Flow<Boolean> = dataStore.data.map { it[IS_DYNAMIC_COLOR] ?: false }
|
||||
val isDynamicColor: Flow<Boolean> = dataStore.data.map { it[IS_DYNAMIC_COLOR] ?: (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) }
|
||||
val themePalette: Flow<String> = dataStore.data.map { it[THEME_PALETTE] ?: "indigo" }
|
||||
|
||||
val updateLastCheckAt: Flow<Long> = dataStore.data.map { it[UPDATE_LAST_CHECK_AT] ?: 0L }
|
||||
val updateLatestVersion: Flow<String> = dataStore.data.map { it[UPDATE_LATEST_VERSION] ?: "" }
|
||||
val updateLastError: Flow<String> = dataStore.data.map { it[UPDATE_LAST_ERROR] ?: "" }
|
||||
val updateCheckIntervalHours: Flow<Int> = dataStore.data.map { it[UPDATE_CHECK_INTERVAL_HOURS] ?: DEFAULT_UPDATE_CHECK_INTERVAL_HOURS }
|
||||
val updateCheckIntervalHours: Flow<Int> = dataStore.data.map { it[UPDATE_CHECK_INTERVAL_HOURS] ?: 24 }
|
||||
val updatePostponeUntil: Flow<Long> = dataStore.data.map { it[UPDATE_POSTPONE_UNTIL] ?: 0L }
|
||||
val updatePostponeVersion: Flow<String> = dataStore.data.map { it[UPDATE_POSTPONE_VERSION] ?: "" }
|
||||
val updateDialogLastShownVersion: Flow<String> = dataStore.data.map { it[UPDATE_DIALOG_LAST_SHOWN_VERSION] ?: "" }
|
||||
@@ -215,6 +321,38 @@ class SettingsStore(context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveActiveProfile(profile: Int) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[ACTIVE_PROFILE] = profile
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveShowSystemApps(enabled: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[SHOW_SYSTEM_APPS] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveLoggingEnabled(enabled: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[LOGGING_ENABLED] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveWdttLink(link: String) {
|
||||
dataStore.edit { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(WDTT_LINK, profile)] = link
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveWdttLinkMode(enabled: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(WDTT_LINK_MODE, profile)] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun save(
|
||||
peer: String,
|
||||
vkHashes: String,
|
||||
@@ -226,102 +364,115 @@ class SettingsStore(context: Context) {
|
||||
noDns: Boolean = false
|
||||
) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[PEER] = peer
|
||||
prefs[VK_HASHES] = vkHashes
|
||||
prefs[SECONDARY_VK_HASH] = secondaryVkHash
|
||||
prefs[WORKERS_PER_HASH] = workersPerHash
|
||||
prefs[PROTOCOL] = protocol
|
||||
prefs[LISTEN_PORT] = listenPort
|
||||
prefs[SNI] = sni
|
||||
prefs[NO_DNS] = noDns
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PEER, profile)] = peer
|
||||
prefs[getProfileKey(VK_HASHES, profile)] = vkHashes
|
||||
prefs[getProfileKey(SECONDARY_VK_HASH, profile)] = secondaryVkHash
|
||||
prefs[getProfileKey(WORKERS_PER_HASH, profile)] = workersPerHash
|
||||
prefs[getProfileKey(PROTOCOL, profile)] = protocol
|
||||
prefs[getProfileKey(LISTEN_PORT, profile)] = listenPort
|
||||
prefs[getProfileKey(SNI, profile)] = sni
|
||||
prefs[getProfileKey(NO_DNS, profile)] = noDns
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveManualPortsEnabled(enabled: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[MANUAL_PORTS_ENABLED] = enabled
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(MANUAL_PORTS_ENABLED, profile)] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun savePorts(serverDtlsPort: Int, serverWgPort: Int, listenPort: Int) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[SERVER_DTLS_PORT] = serverDtlsPort
|
||||
prefs[SERVER_WG_PORT] = serverWgPort
|
||||
prefs[LISTEN_PORT] = listenPort
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(SERVER_DTLS_PORT, profile)] = serverDtlsPort
|
||||
prefs[getProfileKey(SERVER_WG_PORT, profile)] = serverWgPort
|
||||
prefs[getProfileKey(LISTEN_PORT, profile)] = listenPort
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveUserAgent(ua: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[USER_AGENT] = ua
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(USER_AGENT, profile)] = ua
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveDeploy(ip: String, login: String, pass: String, sshPort: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[DEPLOY_IP] = ip
|
||||
prefs[DEPLOY_LOGIN] = login
|
||||
prefs.putSecret(DEPLOY_PASSWORD_ENCRYPTED, DEPLOY_PASSWORD, pass)
|
||||
prefs[DEPLOY_SSH_PORT] = sshPort
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(DEPLOY_IP, profile)] = ip
|
||||
prefs[getProfileKey(DEPLOY_LOGIN, profile)] = login
|
||||
prefs.putSecret(DEPLOY_PASSWORD_ENCRYPTED, DEPLOY_PASSWORD, pass, profile)
|
||||
prefs[getProfileKey(DEPLOY_SSH_PORT, profile)] = sshPort
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveExcludedApps(packages: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[EXCLUDED_APPS] = packages
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(EXCLUDED_APPS, profile)] = packages
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveDetailedLogs(enabled: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[DETAILED_LOGS] = enabled
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(DETAILED_LOGS, profile)] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ Сохранение пароля подключения ═══
|
||||
suspend fun saveConnectionPassword(password: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs.putSecret(CONNECTION_PASSWORD_ENCRYPTED, CONNECTION_PASSWORD, password)
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs.putSecret(CONNECTION_PASSWORD_ENCRYPTED, CONNECTION_PASSWORD, password, profile)
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ Сохранение секретов деплоя ═══
|
||||
suspend fun saveDeploySecrets(mainPass: String, adminId: String, botToken: String, sshPort: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs.putSecret(DEPLOY_MAIN_PASSWORD_ENCRYPTED, DEPLOY_MAIN_PASSWORD, mainPass)
|
||||
prefs.putSecret(DEPLOY_ADMIN_ID_ENCRYPTED, DEPLOY_ADMIN_ID, adminId)
|
||||
prefs.putSecret(DEPLOY_BOT_TOKEN_ENCRYPTED, DEPLOY_BOT_TOKEN, botToken)
|
||||
prefs[DEPLOY_SSH_PORT] = sshPort
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs.putSecret(DEPLOY_MAIN_PASSWORD_ENCRYPTED, DEPLOY_MAIN_PASSWORD, mainPass, profile)
|
||||
prefs.putSecret(DEPLOY_ADMIN_ID_ENCRYPTED, DEPLOY_ADMIN_ID, adminId, profile)
|
||||
prefs.putSecret(DEPLOY_BOT_TOKEN_ENCRYPTED, DEPLOY_BOT_TOKEN, botToken, profile)
|
||||
prefs[getProfileKey(DEPLOY_SSH_PORT, profile)] = sshPort
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ Сохранение proxy mode ═══
|
||||
suspend fun saveProxyMode(mode: String, host: String, port: Int) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[PROXY_MODE] = mode
|
||||
prefs[PROXY_HOST] = host
|
||||
prefs[PROXY_PORT] = port
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(PROXY_MODE, profile)] = mode
|
||||
prefs[getProfileKey(PROXY_HOST, profile)] = host
|
||||
prefs[getProfileKey(PROXY_PORT, profile)] = port
|
||||
}
|
||||
}
|
||||
|
||||
// ═══ Сохранение режима обхода капчи ═══
|
||||
suspend fun saveCaptchaMode(mode: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[CAPTCHA_MODE] = mode
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(CAPTCHA_MODE, profile)] = mode
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveCaptchaSolveMethod(method: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[CAPTCHA_SOLVE_METHOD] = method
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(CAPTCHA_SOLVE_METHOD, profile)] = method
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveWbvCaptchaSolveMethod(method: String) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[CAPTCHA_WBV_SOLVE_METHOD] = method
|
||||
if (prefs[CAPTCHA_MODE] == "wv") {
|
||||
prefs[CAPTCHA_SOLVE_METHOD] = method
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(CAPTCHA_WBV_SOLVE_METHOD, profile)] = method
|
||||
if (prefs[getProfileKey(CAPTCHA_MODE, profile)] == "wv") {
|
||||
prefs[getProfileKey(CAPTCHA_SOLVE_METHOD, profile)] = method
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,47 +480,57 @@ class SettingsStore(context: Context) {
|
||||
// ═══ Сохранение режима списка (ЧС/БС) ═══
|
||||
suspend fun saveIsWhitelist(enabled: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[IS_WHITELIST] = enabled
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(IS_WHITELIST, profile)] = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// Атомарное сохранение обоих параметров для исключения гонки при перезагрузке
|
||||
suspend fun saveExceptionsMode(packages: String, isWhitelist: Boolean) {
|
||||
dataStore.edit { prefs ->
|
||||
prefs[EXCLUDED_APPS] = packages
|
||||
prefs[IS_WHITELIST] = isWhitelist
|
||||
val profile = prefs[ACTIVE_PROFILE] ?: 0
|
||||
prefs[getProfileKey(EXCLUDED_APPS, profile)] = packages
|
||||
prefs[getProfileKey(IS_WHITELIST, profile)] = isWhitelist
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun migrateSecretsToKeystore() {
|
||||
dataStore.edit { prefs ->
|
||||
prefs.migrateSecret(DEPLOY_PASSWORD_ENCRYPTED, DEPLOY_PASSWORD)
|
||||
prefs.migrateSecret(CONNECTION_PASSWORD_ENCRYPTED, CONNECTION_PASSWORD)
|
||||
prefs.migrateSecret(DEPLOY_MAIN_PASSWORD_ENCRYPTED, DEPLOY_MAIN_PASSWORD)
|
||||
prefs.migrateSecret(DEPLOY_ADMIN_ID_ENCRYPTED, DEPLOY_ADMIN_ID)
|
||||
prefs.migrateSecret(DEPLOY_BOT_TOKEN_ENCRYPTED, DEPLOY_BOT_TOKEN)
|
||||
for (profile in 0..2) {
|
||||
prefs.migrateSecret(getProfileKey(DEPLOY_PASSWORD_ENCRYPTED, profile), getProfileKey(DEPLOY_PASSWORD, profile))
|
||||
prefs.migrateSecret(getProfileKey(CONNECTION_PASSWORD_ENCRYPTED, profile), getProfileKey(CONNECTION_PASSWORD, profile))
|
||||
prefs.migrateSecret(getProfileKey(DEPLOY_MAIN_PASSWORD_ENCRYPTED, profile), getProfileKey(DEPLOY_MAIN_PASSWORD, profile))
|
||||
prefs.migrateSecret(getProfileKey(DEPLOY_ADMIN_ID_ENCRYPTED, profile), getProfileKey(DEPLOY_ADMIN_ID, profile))
|
||||
prefs.migrateSecret(getProfileKey(DEPLOY_BOT_TOKEN_ENCRYPTED, profile), getProfileKey(DEPLOY_BOT_TOKEN, profile))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun readSecret(
|
||||
prefs: Preferences,
|
||||
encryptedKey: Preferences.Key<String>,
|
||||
legacyKey: Preferences.Key<String>
|
||||
legacyKey: Preferences.Key<String>,
|
||||
profile: Int
|
||||
): String {
|
||||
return secureStore.decrypt(prefs[encryptedKey]) ?: prefs[legacyKey] ?: ""
|
||||
val profEncryptedKey = getProfileKey(encryptedKey, profile)
|
||||
val profLegacyKey = getProfileKey(legacyKey, profile)
|
||||
return secureStore.decrypt(prefs[profEncryptedKey]) ?: prefs[profLegacyKey] ?: ""
|
||||
}
|
||||
|
||||
private fun MutablePreferences.putSecret(
|
||||
encryptedKey: Preferences.Key<String>,
|
||||
legacyKey: Preferences.Key<String>,
|
||||
value: String
|
||||
value: String,
|
||||
profile: Int
|
||||
) {
|
||||
val profEncryptedKey = getProfileKey(encryptedKey, profile)
|
||||
val profLegacyKey = getProfileKey(legacyKey, profile)
|
||||
if (value.isBlank()) {
|
||||
remove(encryptedKey)
|
||||
remove(legacyKey)
|
||||
remove(profEncryptedKey)
|
||||
remove(profLegacyKey)
|
||||
} else {
|
||||
this[encryptedKey] = secureStore.encrypt(value)
|
||||
remove(legacyKey)
|
||||
this[profEncryptedKey] = secureStore.encrypt(value)
|
||||
remove(profLegacyKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user