Settings: Save server, username, password
This commit is contained in:
@@ -61,6 +61,7 @@ dependencies {
|
|||||||
|
|
||||||
// Kordophone lib
|
// Kordophone lib
|
||||||
implementation project(':backend')
|
implementation project(':backend')
|
||||||
|
implementation 'androidx.security:security-crypto-ktx:1.1.0-alpha06'
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
def nav_version = "2.6.0"
|
def nav_version = "2.6.0"
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ fun SettingsFormView(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var usernameInput by remember { mutableStateOf(TextFieldValue()) }
|
var usernameInput by remember { mutableStateOf(TextFieldValue(userName.value)) }
|
||||||
var passwordInput by remember { mutableStateOf(TextFieldValue()) }
|
var passwordInput by remember { mutableStateOf(TextFieldValue(password.value)) }
|
||||||
SettingsTextField(
|
SettingsTextField(
|
||||||
name = "Authentication",
|
name = "Authentication",
|
||||||
icon = R.drawable.account_circle,
|
icon = R.drawable.account_circle,
|
||||||
|
|||||||
@@ -23,6 +23,15 @@ class SettingsViewModel @Inject constructor(
|
|||||||
private val _passwordPreference: MutableStateFlow<String> = MutableStateFlow("")
|
private val _passwordPreference: MutableStateFlow<String> = MutableStateFlow("")
|
||||||
var passwordPreference = _passwordPreference.asStateFlow()
|
var passwordPreference = _passwordPreference.asStateFlow()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val serverConfig = serverConfigRepository.serverConfig.value
|
||||||
|
serverConfig.serverName?.let { _serverPreference.value = it }
|
||||||
|
serverConfig.authentication?.let {
|
||||||
|
_usernamePreference.value = it.username
|
||||||
|
_passwordPreference.value = it.password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun saveServerPreference(serverName: String) {
|
fun saveServerPreference(serverName: String) {
|
||||||
_serverPreference.value = serverName
|
_serverPreference.value = serverName
|
||||||
|
|
||||||
@@ -36,7 +45,7 @@ class SettingsViewModel @Inject constructor(
|
|||||||
_passwordPreference.value = password
|
_passwordPreference.value = password
|
||||||
|
|
||||||
serverConfigRepository.applyConfig {
|
serverConfigRepository.applyConfig {
|
||||||
authentication = ServerAuthentication(username, password)
|
this.authentication = ServerAuthentication(username, password)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,102 @@
|
|||||||
package net.buzzert.kordophonedroid.ui.shared
|
package net.buzzert.kordophonedroid.ui.shared
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
|
import androidx.security.crypto.MasterKey
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import java.lang.reflect.Constructor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
|
||||||
data class ServerConfig(
|
data class ServerConfig(
|
||||||
var serverName: String? = null,
|
var serverName: String? = null,
|
||||||
var authentication: ServerAuthentication? = null,
|
var authentication: ServerAuthentication? = null,
|
||||||
)
|
) {
|
||||||
|
companion object {
|
||||||
|
private const val SHARED_PREF_NAME = "KordophonePreferences"
|
||||||
|
|
||||||
|
fun loadFromSettings(context: Context): ServerConfig {
|
||||||
|
val prefs = getSharedPreferences(context)
|
||||||
|
return ServerConfig(
|
||||||
|
serverName = prefs.getString("serverName", null),
|
||||||
|
authentication = ServerAuthentication.loadFromEncryptedSettings(context)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSharedPreferences(context: Context): SharedPreferences {
|
||||||
|
return context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveToSettings(context: Context) {
|
||||||
|
val prefs = getSharedPreferences(context)
|
||||||
|
prefs.edit {
|
||||||
|
putString("serverName", serverName)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
authentication?.saveToEncryptedSettings(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class ServerAuthentication(
|
data class ServerAuthentication(
|
||||||
val username: String,
|
val username: String,
|
||||||
val password: String,
|
val password: String,
|
||||||
)
|
) {
|
||||||
|
companion object {
|
||||||
|
fun loadFromEncryptedSettings(context: Context): ServerAuthentication? {
|
||||||
|
val prefs = getEncryptedSharedPreferences(context)
|
||||||
|
|
||||||
|
val username = prefs.getString("username", null)
|
||||||
|
val password = prefs.getString("password", null)
|
||||||
|
if (username != null && password != null) {
|
||||||
|
return ServerAuthentication(username, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEncryptedSharedPreferences(context: Context): SharedPreferences {
|
||||||
|
val masterKey = MasterKey.Builder(context)
|
||||||
|
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return EncryptedSharedPreferences(
|
||||||
|
context,
|
||||||
|
"secrets",
|
||||||
|
masterKey,
|
||||||
|
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||||
|
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveToEncryptedSettings(context: Context) {
|
||||||
|
val prefs = getEncryptedSharedPreferences(context)
|
||||||
|
prefs.edit {
|
||||||
|
putString("username", username)
|
||||||
|
putString("password", password)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class ServerConfigRepository @Inject constructor() {
|
class ServerConfigRepository @Inject constructor(
|
||||||
|
@ApplicationContext val context: Context,
|
||||||
|
) {
|
||||||
// TODO: Initial config should be loaded from device settings.
|
// TODO: Initial config should be loaded from device settings.
|
||||||
private val _serverConfig = MutableStateFlow(ServerConfig()) // Initial config
|
private val _serverConfig = MutableStateFlow(ServerConfig.loadFromSettings(context)) // Initial config
|
||||||
val serverConfig: StateFlow<ServerConfig> = _serverConfig
|
val serverConfig: StateFlow<ServerConfig> = _serverConfig
|
||||||
|
|
||||||
fun applyConfig(applicator: ServerConfig.() -> Unit) {
|
fun applyConfig(applicator: ServerConfig.() -> Unit) {
|
||||||
val config = _serverConfig.value.copy()
|
val config = _serverConfig.value.copy()
|
||||||
_serverConfig.value = config.apply(applicator)
|
_serverConfig.value = config.apply(applicator)
|
||||||
|
_serverConfig.value.saveToSettings(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user